Build a module from a repository and a path within it
The builder cloned a repository and read the manifest at its root, which means one repository per module. Nothing we have is shaped that way, so the builder could be asked to build nothing that exists (novox/hq ADR 0069). The path travels the whole way — named when asking, carried in the request, used to read the manifest and as the context everything is produced from, echoed back in the result, and recorded as part of where a module came from. Without that last part the mesh could notice a module was behind its source and then be unable to rebuild it, which is the worst of both. A path climbing out of the clone is refused: a machine whose job is building other people's repositories must not read whatever else is on its disk. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -152,16 +152,20 @@ func answer(ctx context.Context, channel *amqp.Channel, publisher builder.Publis
|
||||
}
|
||||
|
||||
result := link.BuildResult{
|
||||
ID: request.ID, Repository: request.Repository, Ref: request.Ref, On: on,
|
||||
ID: request.ID, Repository: request.Repository, Path: request.Path,
|
||||
Ref: request.Ref, On: on,
|
||||
}
|
||||
fmt.Printf("building %s", request.Repository)
|
||||
if request.Path != "" {
|
||||
fmt.Printf(" at %s", request.Path)
|
||||
}
|
||||
if request.Ref != "" {
|
||||
fmt.Printf(" at %s", request.Ref)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
built, err := builder.Build(ctx, builder.Command, publisher,
|
||||
request.Repository, request.Ref, workspace)
|
||||
request.Repository, request.Path, request.Ref, workspace)
|
||||
if err != nil {
|
||||
// A failure is a result. A build that fails and says nothing is indistinguishable from a
|
||||
// builder that is not running, and those want completely different responses.
|
||||
|
||||
@@ -33,6 +33,9 @@ import (
|
||||
func buildCommand(ctx context.Context, args []string) error {
|
||||
set := flag.NewFlagSet("build", flag.ContinueOnError)
|
||||
ref := set.String("ref", "", "the branch, tag or commit to build")
|
||||
// A module is a repository and a path within it (novox/hq ADR 0069). Empty is the repository's
|
||||
// root, which is the ordinary case and why this is a flag rather than a second argument.
|
||||
path := set.String("path", "", "the module's directory inside the repository")
|
||||
wait := set.Duration("wait", 10*time.Minute, "how long to wait for a builder to answer")
|
||||
dryRun := set.Bool("dry-run", false, "build and print the manifest, recording nothing")
|
||||
// Every module whose source has moved, rather than one named repository.
|
||||
@@ -58,9 +61,9 @@ func buildCommand(ctx context.Context, args []string) error {
|
||||
}
|
||||
|
||||
if *dryRun {
|
||||
return buildAndShow(ctx, positionals[0], *ref, *wait)
|
||||
return buildAndShow(ctx, positionals[0], *path, *ref, *wait)
|
||||
}
|
||||
return buildOne(ctx, positionals[0], *ref, *wait)
|
||||
return buildOne(ctx, positionals[0], *path, *ref, *wait)
|
||||
}
|
||||
|
||||
// buildFrom turns what a builder said into what the mesh keeps.
|
||||
@@ -300,7 +303,7 @@ func buildBehind(ctx context.Context, wait time.Duration) error {
|
||||
// Its own recorded ref, not its head commit: a module tracking a branch should be built
|
||||
// from that branch, and pinning to the commit the mesh happened to notice would quietly
|
||||
// turn a tracked branch into a pin.
|
||||
if err := buildOne(ctx, e.Source.Repository, e.Source.Ref, wait); err != nil {
|
||||
if err := buildOne(ctx, e.Source.Repository, e.Source.Path, e.Source.Ref, wait); err != nil {
|
||||
fmt.Printf(" %v\n", err)
|
||||
failed = append(failed, e.Manifest.Module)
|
||||
}
|
||||
@@ -318,7 +321,7 @@ func buildBehind(ctx context.Context, wait time.Duration) error {
|
||||
// buildOne asks a build machine for one repository and records everything that came back.
|
||||
//
|
||||
// Separated from the command so `--behind` can walk a list without a second path to the same act.
|
||||
func buildOne(ctx context.Context, repository, ref string, wait time.Duration) error {
|
||||
func buildOne(ctx context.Context, repository, path, ref string, wait time.Duration) error {
|
||||
ident, err := openIdentity(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -336,11 +339,15 @@ func buildOne(ctx context.Context, repository, ref string, wait time.Duration) e
|
||||
request := link.BuildRequest{
|
||||
ID: fmt.Sprintf("%s-%d", "build", time.Now().UnixNano()),
|
||||
Repository: repository,
|
||||
Path: path,
|
||||
Ref: ref,
|
||||
}
|
||||
fmt.Printf("asked for %s", request.Repository)
|
||||
if path != "" {
|
||||
fmt.Printf(" at %s", path)
|
||||
}
|
||||
if ref != "" {
|
||||
fmt.Printf(" at %s", ref)
|
||||
fmt.Printf(" on %s", ref)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
@@ -383,7 +390,7 @@ func buildOne(ctx context.Context, repository, ref string, wait time.Duration) e
|
||||
// Recorded with where it came from, so "is this current?" is answerable without building it
|
||||
// again (novox/hq ADR 0009).
|
||||
if err := inv.RegisterModule(ctx, manifest, inventory.Source{
|
||||
Repository: result.Repository, Ref: result.Ref,
|
||||
Repository: result.Repository, Path: result.Path, Ref: result.Ref,
|
||||
BuiltFrom: result.Commit, Head: result.Commit,
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -395,7 +402,7 @@ func buildOne(ctx context.Context, repository, ref string, wait time.Duration) e
|
||||
}
|
||||
|
||||
// buildAndShow builds and prints the manifest without recording anything.
|
||||
func buildAndShow(ctx context.Context, repository, ref string, wait time.Duration) error {
|
||||
func buildAndShow(ctx context.Context, repository, path, ref string, wait time.Duration) error {
|
||||
ident, err := openIdentity(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -408,7 +415,8 @@ func buildAndShow(ctx context.Context, repository, ref string, wait time.Duratio
|
||||
defer server.Close()
|
||||
|
||||
result, err := link.RequestBuild(ctx, server.Channel(), link.BuildRequest{
|
||||
ID: fmt.Sprintf("%s-%d", "build", time.Now().UnixNano()), Repository: repository, Ref: ref,
|
||||
ID: fmt.Sprintf("%s-%d", "build", time.Now().UnixNano()),
|
||||
Repository: repository, Path: path, Ref: ref,
|
||||
}, wait)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user