feat(deploy): P2 — source=image (BYO prebuilt image), flag-gated OFF#221
Merged
Conversation
…s fields
First, safe, additive slice of P2 (BYO-image deploys, PLAN-deploy-multisource):
- migration 064: deployments.source ('tarball'|'image'|'git', default tarball),
image_ref, registry_creds_enc — all DEFAULT-safe so existing rows/tarball
deploys are unchanged; CHECK constrains source.
- compute.DeployOptions: Source, ImageRef, RegistryAuth fields (ignored by the
existing tarball path until the skip-Kaniko branch lands).
Foundation only — the compute skip-Kaniko branch + handler source-dispatch +
plan flag + tests land next (the compute branch changes the deploy path and
needs cluster validation, so it ships behind the byo_image flag).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
K8sProvider.Deploy branches on opts.Source: for "image" it deploys opts.ImageRef directly — no buildImage (no Kaniko Job, MinIO upload, or build NetworkPolicy). setupTenantNamespace still creates the per-deploy namespace + security primitives; ensureImagePullSecret puts a "ghcr-pull" pull secret in it (BYO RegistryAuth → caller's creds; else copy the platform secret). applyDeploymentInNS/service/ingress are shared with the tarball path. Tarball path unchanged. Initial-deploy only; redeploy-with-image is P2.1. Persistence (models) + handler source-dispatch + byo_image flag + tests land next on this branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the source=image vertical slice (PLAN-deploy-multisource):
- models: persist + read source/image_ref/registry_creds_enc (migration 064)
via the shared deploymentColumns/scanDeployment + CreateDeployment.
- New handler: dispatch on `source` ('tarball' default | 'image'); for image,
validateImageRef (fully-qualified host required — no ambiguous bare names)
+ AES-256-GCM-encrypt optional BYO registry_creds; tarball path unchanged.
- runDeploy: source=image sets DeployOptions.{Source,ImageRef,RegistryAuth}
(decrypt creds), no tarball.
- deploymentToMap: source + image_ref + registry_creds_set (creds never echoed).
GATING: the skip-Kaniko compute branch changes the live deploy path and can't
be CI-validated (no real cluster), so it's behind a config flag,
DEPLOY_SOURCE_IMAGE_ENABLED, DEFAULT FALSE — source=image returns 501 until an
operator enables it post-canary. Tarball deploys are completely unaffected.
source=image is naturally Hobby+ (anon/free have deployments_apps=0).
Tests: validateImageRef + deploymentSourceOrDefault unit tests. build+vet green.
Follow-up (flag off, so not user-facing yet): flag-ON image integration test +
openapi/llms.txt/MCP contract sync; redeploy-with-image is P2.1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
White-box test: source=image map carries source/image_ref/registry_creds_set (and never the raw creds); tarball deploys omit the image-only keys. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anch Close the 100%-patch coverage gaps CI flagged on the P2 source=image work: - config: TestLoad_DeploySourceImageEnabled (true/off matrix) + default-false assert + DEPLOY_SOURCE_IMAGE_ENABLED added to allKeys() (covers config.go flag-true branch). - handlers: extract applyImageSourceOpts from runDeploy and unit-test it (image/no-creds/bad-ciphertext/bad-key paths) + deploymentToMap image echo. - handlers integration: source switch end-to-end — flag-off 501, invalid source 400, flag-on invalid image_ref 400, flag-on happy 202 (asserts source/image_ref echo, creds never echoed, async runDeploy drives the row healthy via the noop provider). - k8s: TestDeploy_ImageSource_SkipsBuildAndDeploysRef (fake clientset) covers the skip-Kaniko image branch + ensureImagePullSecret BYO-creds path. - testhelpers: variadic config-mutator on NewTestAppWithServices + 064 deploy source columns in the test DDL. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
golangci-lint's analysis cache was masking 37 pre-existing SA5011
false-positives across the repo's test files; any cache-busting change
(here, the new deploy source=image tests) surfaces them and reds lint on
every PR. SA5011 in tests fires on the idiomatic
`got := f(); if got == nil { t.Fatalf(...) }; got.X` pattern — a nil
deref in a test panics and fails loudly, so it carries no production
signal. Suppressed by-check (SA5011) in _test.go only, mirroring the
existing SA1019/QF1001 by-check suppressions; production SA5011 still
fails the build. Verified: full `golangci-lint run ./...` → 0 issues.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r arms) - deploy.go: extract encryptRegistryCreds helper, collapsing the registry-creds encrypt block to a single handler error branch (the prior crypto.Encrypt error arm was unreachable with a valid key — now returned verbatim). Unit-test the helper (bad-key + round-trip) + integration test the handler 503 via a misconfigured AES_KEY (AES parsing is request-time so the app still builds). - k8s: reactor-driven tests for the source=image Deploy error arms (setup-namespace, pull-secret), the ensureImagePullSecret empty-creds copy + already-exists update arms, and the tarball build-error + post-build setup-namespace arms (build Job auto-completed via attachJobCompleteReactor). Verified all flagged client.go lines (1060-67,1071-72,1078-79,1617-27) covered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-package coverage only credits the testhelpers package when an in-package test exercises a line; handler tests pass feature-flag mutators but run in package handlers_test, so the new mutator loop showed as uncovered in diff-cover. Add an in-package smoke test that passes a nil + a real mutator, covering the loop and its nil-skip guard. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scanDeployment now reads source/image_ref/registry_creds_enc (mig 064), so the hand-maintained deploymentColumnsList + AddRow rows in the redeploy-in-place mock test must carry the 3 new columns or sqlmock Scan fails with a 24-vs-27 destination-count mismatch. Adds the columns + a 'tarball','','' trailer to each of the three mocked rows. (Only sqlmock-backed deployment-row test; real-DB tests get the columns from the testhelpers DDL.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…codes Two more failures from the mig-064 deployment columns: - models: deploymentMockCols()/deploymentMockRow() (shared by ~10 model tests) scanned 24 cols; add source/image_ref/registry_creds_enc so scanDeployment's 27 destinations match. (Completes the rule-16 enumeration: the only full deployment-row mocks are coverage_provision_gate_test.go's helper, coverage_deployment_test.go via that helper, and the redeploy mock test.) - handlers: the registry-iterating TestErrorCode_HasAgentAction gate requires every emitted code to carry agent_action. Add entries for the 4 new deploy codes — invalid_source, source_image_disabled, invalid_image_ref, encrypt_failed — with actionable agent copy (not allowlist stubs). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 2 of the multi-source deploy plan. Adds
source=imageto /deploy/new: deploy a prebuilt image (e.g. from GitHub CI) with no upload/Kaniko build. migration 064 (source/image_ref/registry_creds_enc), compute skip-Kaniko branch + per-deploy pull secret, handler dispatch + validateImageRef + AES-encrypted BYO registry creds, deploymentToMap markers (creds never echoed).Flag-gated OFF (
DEPLOY_SOURCE_IMAGE_ENABLED=falsedefault): the skip-Kaniko branch changes the live deploy path and can't be CI-validated (no real cluster), so it returns 501 until an operator enables it post-canary. Tarball deploys are unaffected.Unit tests for the validators; flag-ON image integration test + openapi/llms/MCP contract sync are the immediate follow-up (flag off → not user-facing yet). 🤖 Generated with Claude Code