Skip to content

feat: pull production image privately - #31

Merged
cooper (czxtm) merged 1 commit into
mainfrom
agent/template-ghcr-pull-secret
Oct 10, 2026
Merged

cooper (czxtm) merged 1 commit into
mainfrom
agent/template-ghcr-pull-secret

Conversation

@czxtm

Copy link
Copy Markdown
Member

Summary

Configure only the production Deployment to use the namespace-local template-ghcr-pull imagePullSecret. The GHCR package remains private.

Dependency

The companion GitOps PR provisions the matching encrypted Kubernetes Secret before ArgoCD deploys this overlay.

Validation

  • YAML parsing and git diff --check passed

@czxtm
cooper (czxtm) merged commit 7e960ff into main Oct 10, 2026
1 check passed
@czxtm
cooper (czxtm) deleted the agent/template-ghcr-pull-secret branch October 10, 2026 10:53
@linear-code

linear-code Bot commented Oct 10, 2026

Copy link
Copy Markdown

ENG-997

@darkmatteragent darkmatteragent left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I independently re-verified the analyze stage's approve and concur: the two-file diff is correct, correctly scoped, and introduces no provable defect. I kept zero findings, and I did not adopt any of the "unanswered question" gaps as findings because none is anchored to a demonstrated fault.

What I traced from the changed lines to their consumers:

  1. Patch target matches exactly one resource. ghcr-pull-secret.patch.yaml is a bare strategic-merge patch (registered under patches: with only path:, no target:), so kustomize matches it by apiVersion/kind/name. I enumerated every Deployment in the production overlay's resource closure (../../deploy/kubernetes/base + ../../deploy/kubernetes/database): the only one named agent-demo-web is ops/deploy/kubernetes/base/web-deployment.yaml (apps/v1). web-service.yaml carries the same name but kind Service, and the database overlay contains only a CNPG Cluster, ScheduledBackup, and NetworkPolicy — none can collide. So the build cannot fail on a missing or ambiguous target.

  2. No sibling-patch interaction. replicas.patch.yaml touches only spec.replicas, resources.patch.yaml only spec.template.spec.containers[name=web].resources (a merge-by-name list, so it will not clobber imagePullSecrets), and runtime-config.patch.yaml targets a different kind (ConfigMap agent-demo-runtime). Strategic merges over disjoint fields are order-independent, so the new entry's first position in the patches list is harmless.

  3. The private-image claim holds on the consumer side. Production rewrites ghcr.io/example/agent-demo:replace-me to ghcr.io/darkmatter/template@sha256:7985fb…, and .github/workflows/publish-production-image.yaml publishes exactly ghcr.io/darkmatter/template. So the pull secret lands on the one workload that actually consumes the private package; the digest pin also satisfies ops/policies/security/image-policy.yaml. Dev/staging still use the ghcr.io/example/agent-demo placeholder, consistent with the PR body's "production-only" requirement, and the CNPG cluster image is public — nothing else needs the secret.

  4. The out-of-repo Secret is documented repo practice, not an invariant inversion. AGENTS.md (Secrets section) says environment compositions should reference secrets through their GitOps controller rather than copying values into ops/environments/, and ops/README.md records the same model for template-postgres-backup-r2, which is referenced by name in ops/deploy/kubernetes/database/cluster.yaml and provisioned in darkmatter/gitops. template-ghcr-pull follows the same convention (and the template- prefix). The PR body explicitly declares the companion PR and its required ordering, so raising "the Secret might be missing" would restate the declared dependency and speculate about a PR outside the evidence.

  5. No collateral breakage. The digest-pinning step in the publish workflow regex-matches ^ digest: sha256:[0-9a-f]{64}$; the added - path: ghcr-pull-secret.patch.yaml line is differently indented and does not disturb it. ops/bin/deploy only runs kubectl kustomize, unchanged. The new file matches the sibling patches' YAML style, so bun run fmt:check (oxfmt, 80 width, ops/** not excluded) has nothing to reformat. The patch needs no metadata.namespace — unspecified namespace matches, and the overlay assigns template-production to all resources.

Risks I considered and deliberately did not raise: (a) if the companion Secret is absent/misnamed, the rollout stalls in ImagePullBackOff — but that ordering is declared in the PR body, is recoverable once the Secret lands, and mirrors the accepted R2-credential precedent, so it is the documented design, not a defect; (b) adding imagePullSecrets mutates the pod template and rolls all three replicas — inherent, expected k8s behavior with the default RollingUpdate, not an outage; (c) CI has no kustomize overlay build and mergeable_state: unstable is undiagnosed — both pre-existing gaps outside this diff's lines and not reportable against it.

Conclusion: approve. The change is additive, production-only, credential-free, matches a live target, and follows the repo's documented GitOps secret-referencing model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants