Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions bootstrap_template_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -61,7 +61,7 @@ func TestBootstrapImageAlwaysReconcilesRuntimeAccess(t *testing.T) {
t.Fatalf("migration command present = %t, want %t", hasMigration, test.withMigrations)
}

accessSQL := renderBuilderTemplate(t, "templates/builder/runtime-access.sql.tmpl", parameters)
accessSQL := renderRuntimeAccessTemplate(t, parameters)
for _, required := range []string{
"NOBYPASSRLS",
"NOCREATEROLE",
Expand DownExpand Up@@ -100,11 +100,7 @@ func TestBootstrapImageBuildsWhenDockerOmitsTargetArchitecture(t *testing.T) {
); err != nil {
t.Fatal(err)
}
builderDir := filepath.Join(root, "builder")
if err := os.MkdirAll(builderDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(builderDir, "runtime-access.sql"), []byte("SELECT 1;\n"), 0o644); err != nil {
if err := os.WriteFile(filepath.Join(root, "runtime-access.sql"), []byte("SELECT 1;\n"), 0o644); err != nil {
t.Fatal(err)
}
tag := fmt.Sprintf("service-postgres-bootstrap-targetarch-test:%d", time.Now().UnixNano())
Expand All@@ -126,7 +122,7 @@ func TestRuntimeAccessTemplateUsesDelegatedRolesAsExclusiveWriteAuthority(t *tes
ReadWriteRoles: []string{"app_tenant", "app_worker"},
}

accessSQL := renderBuilderTemplate(t, "templates/builder/runtime-access.sql.tmpl", parameters)
accessSQL := renderRuntimeAccessTemplate(t, parameters)
for _, forbidden := range []string{
"GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES",
"GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES",
Expand DownExpand Up@@ -158,7 +154,7 @@ func TestRuntimeAccessTemplatePreservesDirectWriterWithoutDelegatedRoles(t *test
Schemas: []string{"public"},
}

accessSQL := renderBuilderTemplate(t, "templates/builder/runtime-access.sql.tmpl", parameters)
accessSQL := renderRuntimeAccessTemplate(t, parameters)
for _, required := range []string{
"GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES",
"GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES",
Expand All@@ -172,8 +168,16 @@ func TestRuntimeAccessTemplatePreservesDirectWriterWithoutDelegatedRoles(t *test
}

func renderBuilderTemplate(t *testing.T, name string, parameters DockerTemplating) string {
return renderTemplate(t, builderFS, name, parameters)
}

func renderRuntimeAccessTemplate(t *testing.T, parameters DockerTemplating) string {
return renderTemplate(t, runtimeFS, "templates/runtime/runtime-access.sql.tmpl", parameters)
}

func renderTemplate(t *testing.T, fsys fs.FS, name string, parameters DockerTemplating) string {
t.Helper()
source, err := fs.ReadFile(builderFS, name)
source, err := fs.ReadFile(fsys, name)
if err != nil {
t.Fatal(err)
}
Expand Down
7 changes: 6 additions & 1 deletion build_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -79,10 +79,15 @@ func TestBuildEmitsRecipeToOutputDirectory(t *testing.T) {
// The rendered tree is a self-contained context: a consumer with no codefly
// toolchain can build it from the emitted files alone.
require.FileExists(t, filepath.Join(outputDirectory, "builder", "Dockerfile"))
require.FileExists(t, filepath.Join(outputDirectory, "builder", "runtime-access.sql"))
require.FileExists(t, filepath.Join(outputDirectory, "migrations", "1_create_table.up.sql"))
require.FileExists(t, filepath.Join(outputDirectory, "migrations", "1_create_table.down.sql"))

// runtime-access.sql the Dockerfile COPYs must sit at the context root beside
// migrations/, not inside the builder/ recipe-metadata directory the CLI drops
// from the staged build context — otherwise the COPY fails to resolve.
require.FileExists(t, filepath.Join(outputDirectory, "runtime-access.sql"))
require.NoFileExists(t, filepath.Join(outputDirectory, "builder", "runtime-access.sql"))

// The plan the agent emits verifies against the tree it wrote, so the CLI
// builds it without the recipe drifting from the inventory.
require.NoError(t, services.VerifyDockerBuildPlan(outputDirectory, plan))
Expand Down
21 changes: 21 additions & 0 deletions builder.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -166,6 +166,10 @@ func (s *Builder) Build(ctx context.Context, req *builderv0.BuildRequest) (*buil
return s.Builder.BuildError(err)
}

if err = s.renderRuntimeAccess(ctx, docker, s.Location); err != nil {
return s.Builder.BuildError(err)
}

builder, err := dockerhelpers.NewBuilder(dockerhelpers.BuilderConfiguration{
Root: s.Location,
Dockerfile: "builder/Dockerfile",
Expand DownExpand Up@@ -204,6 +208,13 @@ func (s *Builder) buildRecipe(ctx context.Context, outputDirectory string, img *
return s.Builder.BuildError(err)
}

// runtime-access.sql is a build-context file the Dockerfile COPYs, so it lives
// at the context root beside migrations/ — not inside builder/, which the CLI
// treats as recipe metadata and drops from the staged build context.
if err := s.renderRuntimeAccess(ctx, docker, outputDirectory); err != nil {
return s.Builder.BuildError(err)
}

if s.WithMigration() {
// The Dockerfile's COPY migrations needs the directory to exist even when
// no migrations are authored yet, so create it before copying rather than
Expand DownExpand Up@@ -232,6 +243,13 @@ func (s *Builder) buildRecipe(ctx context.Context, outputDirectory string, img *
return s.Builder.BuildResponse()
}

// renderRuntimeAccess renders runtime-access.sql into the build context root, the
// directory docker builds from. The Dockerfile COPYs it from there, so it must
// sit beside migrations/ rather than under builder/.
func (s *Builder) renderRuntimeAccess(ctx context.Context, docker DockerTemplating, contextRoot string) error {
return s.Templates(ctx, docker, services.WithTemplate(runtimeFS, "runtime", "").WithDestination("%s", contextRoot))
}

// copyTree copies every regular file under from into to, preserving the relative
// layout. Directory entries themselves are not created here; the caller
// provisions any directory a build step requires to exist.
Expand DownExpand Up@@ -529,5 +547,8 @@ var factoryFS embed.FS
//go:embed templates/builder
var builderFS embed.FS

//go:embed templates/runtime
var runtimeFS embed.FS

//go:embed templates/deployment
var deploymentFS embed.FS
2 changes: 1 addition & 1 deletion templates/builder/Dockerfile.tmpl
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,7 @@ COPY . .
{{- if .WithMigration }}
COPY migrations /app/migrations
{{- end }}
COPY builder/runtime-access.sql /app/runtime-access.sql
COPY runtime-access.sql /app/runtime-access.sql

CMD set -eu; \
until pg_isready -d "${{.MigrationConnectionKeyHolder}}" >/dev/null 2>&1; do sleep 2; done; \
Expand Down
Loading