Skip to content

chore(cascade): develop -> stage (secret metadata-leak fix) - #1007

Merged
evereq merged 2 commits into
stagefrom
develop
Aug 7, 2026
Merged

chore(cascade): develop -> stage (secret metadata-leak fix)#1007
evereq merged 2 commits into
stagefrom
develop

Conversation

@evereq

@evereq evereq commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Standard cascade. Carries #1006 (server-side apply for the two Secret-creating steps in deploy_k8s.yaml, so the credential is no longer duplicated into last-applied-configuration metadata) plus one content-neutral docs commit (72dd99eb, Star History link) that was stranded on develop.

Content diff between the branches before this PR was 0 files — stage was 191 commits ahead but tree-identical — so this is a clean cascade, not a divergence.

🤖 Generated with Claude Code

evereq and others added 2 commits August 4, 2026 23:53
Charts now render from https://stats-github.ever.works/svg instead of the shared public
api.star-history.com, so they are backed by our own GitHub PAT quota and our
own uptime, and are cached for 24h at the edge.

Also fixes the repo name: the chart pointed at ever-co/directory-web-template,
which is not this repo (it lives in ever-works).

README-only change, so [skip ci] keeps it off the build runners.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tl apply (#1006)

Both secret-creating steps in deploy_k8s.yaml piped into a plain
`kubectl apply -f -`. Client-side apply stamps the entire object into a
`kubectl.kubernetes.io/last-applied-configuration` annotation, so for a Secret
the payload ends up a second time, in cleartext-base64, in the object's
METADATA - where it leaks through `-o yaml` dumps, Velero snapshots and any
tool that redacts `data:` but renders annotations verbatim.

This was found live on 2026-08-07: 109 of 122 dockerconfigjson secrets on
ever-k8s carried the annotation with a usable GHCR token in it.

- `${WORK_SLUG}-pull` duplicated the registry credential.
- `${WORK_SLUG}-runtime-env` is worse: it materialises EVERY forwarded repo
  secret (DATABASE_URL, AUTH_SECRET, COOKIE_SECRET, ...), so it duplicated the
  app's whole secret set.

Both now use `kubectl apply --server-side --force-conflicts`, which records
ownership in `.metadata.managedFields` and writes no annotation.
`replace --force` also avoids it but deletes and recreates the object, leaving
a window where a starting pod finds no pull secret.

The namespace, deployment, service and ingress applies are deliberately left
as client-side apply - they carry no secret material.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@evereq
evereq merged commit b4c775a into stage Aug 7, 2026
7 of 8 checks passed
@cursor

cursor Bot commented Aug 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bc6d9949-0819-4929-bd96-23d7a7ef1556

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change switches image-pull and runtime-environment Secret provisioning to server-side apply and updates the README Star History links. Server-side apply prevents new client-side last-applied annotations, but existing fixed-name Secrets are not cleaned up and can retain credential-bearing metadata.

T-Rex validation blocked

The focused Kubernetes upgrade-path check could not complete because the disposable Kubernetes v1.31 API server could not select a network address from the runner's default routes. The check must be rerun on a Kubernetes-capable runner or disposable cluster to exercise creation of a legacy Secret followed by the server-side update.

Confidence Score: 3/5

Not merge-safe until existing legacy Secret annotations are removed during migration.

The final findings contain one P1 security issue, which maps to a score of 3 under the required scoring table. The Kubernetes runtime check was attempted but could not reach a usable API server, so it does not alter the score.

Files Needing Attention: .github/workflows/deploy_k8s.yaml needs an explicit migration step to remove the legacy last-applied annotation from both fixed-name Secrets.

Security Review

Existing Secrets created through client-side apply can retain their kubectl.kubernetes.io/last-applied-configuration annotation after this deployment change. That annotation may contain base64-encoded registry or runtime credentials and can be exposed by metadata-rendering backups, dumps, and tools that redact Secret data but not annotations.

T-Rex T-Rex Logs

What T-Rex did

  • The focused upgrade-path validator was authored to create a Secret with client-side apply, run kubectl apply --server-side --force-conflicts -f -, and inspect the resulting annotation.
  • The validation attempt proceeded to verify the post-update annotation, but the disposable Kubernetes API server failed to start after five attempts because it could not select a network address from the runner's default routes.
  • As a result, neither legacy Secret creation nor the post-update annotation inspection reached the Kubernetes API server.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "fix(ci): stop leaking secrets into k8s m..." | Re-trigger Greptile

--docker-password="$REGISTRY_PASSWORD" \
-n "$NAMESPACE" \
--dry-run=client -o yaml | kubectl apply -f -
--dry-run=client -o yaml | kubectl apply --server-side --force-conflicts -f -

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 security Legacy secret annotation remains

When these fixed-name Secrets already exist from a client-side apply, server-side apply updates them without removing the legacy kubectl.kubernetes.io/last-applied-configuration annotation, causing registry and application credentials to remain exposed through metadata-rendering dumps, snapshots, and tools. How this was verified: Both Secrets are updated in place, while no workflow command removes the pre-existing annotation.

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.

1 participant