Skip to content

feat(lifecycle): add the one-shot ownership bootstrap workflow - #1249

Merged
mashkovd merged 4 commits into
mainfrom
feat/lifecycle-bootstrap-workflow
Sep 14, 2026
Merged

mashkovd merged 4 commits into
mainfrom
feat/lifecycle-bootstrap-workflow

Conversation

@mashkovd

Copy link
Copy Markdown
Member

Part of mctlhq/.github#57 — step E2. Pairs with the bootstrap module in mctl-agents
(E1, separate PR).

Why

Before the observe soak starts, the ownership store has to hold a row for every entity
the old mechanism already knows about. Otherwise every comparison reads
store-permits-old-forbids — the one dangerous class — and the measurement is
swamped by its own migration.

Not a CronWorkflow

Operator-submitted, and there is deliberately no schedule. This is a migration step; a
migration that runs on a timer is a reconciler nobody designed.

argo submit --from clusterworkflowtemplate/lifecycle-bootstrap -n argo-workflows -p dry_run=true

Two runs, in order: dry_run=true prints a JSON report and writes nothing; review every
row against the store and live Temporal, then dry_run=false.

The safe default is the default

dry_run defaults to "true", and the shell compares against the literal "false"
rather than matching "true". A typo must not write to the ownership store — matching
the positive would make a misspelled flase apply. The parameter reaches the script as
an env var and is never interpolated into the body.

What was dropped from the shepherd's scaffolding

The clone initContainer is the shepherd CWFT's, pinned GitHub host keys included. Removed:
the OAuth token, the per-tick cost cap, the implementer subprocess and therefore the
TMPDIR clone directory. The checkout is read-only here — .status.yaml is an input —
so there is no push step and no write mutex, and activeDeadlineSeconds is 15 minutes
rather than two hours.

MCTL_TOKEN is not optional here, unlike on the shepherd: the batch read and the
acquire route are both admin-gated, and a bootstrap that cannot authenticate reads UNKNOWN
for every entity and aborts — safe, but a wasted run with a confusing report.

MCTL_API_BASE_URL is deliberately not set, matching the shepherd: the default lives
in orchestrator/temporal/mctl_client.py. Pinning it in one template of several is how
the two drift, and the resulting failure is quiet — a bootstrap pointed at another
environment's API imports owners derived from that cluster's liveness.

Before submitting it

The agent_image default is 1.45.0, which does not contain
orchestrator/lifecycle/bootstrap.py. Bump it to the release that does before the first
run — or pass -p agent_image=.... Merging this template changes nothing on its own: it
is inert until somebody submits it.

Verification

argo lint --offline platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml
✔ no linting errors found!

Then, once the image carries the module: a dry_run=true submission whose report an
operator reads row by row against mctl_get_lifecycle_ownership and live Temporal.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RUQTbQvUQjwbDFd7Nq9bvC

Before the observe soak starts, the store has to hold a row for every
entity the old mechanism already knows about. Otherwise every comparison
reads store-permits-old-forbids -- the one DANGEROUS class -- and the
measurement is swamped by its own migration.

Operator-submitted, never scheduled. There is no CronWorkflow for this
and there should not be: it is a migration step, and a migration that
runs on a timer is a reconciler nobody designed.

dry_run defaults to "true", and the shell compares against the literal
"false" rather than matching "true": a typo must not write to the
ownership store, and matching the positive would make a misspelled
"flase" apply. The parameter reaches the script as an env var, never
interpolated into the body.

The clone scaffolding is the shepherd CWFT's, including the pinned GitHub
host keys, minus everything SDK- and budget-related: no OAuth token, no
per-tick cost cap, no implementer subprocess and so no TMPDIR clone
directory. The checkout is read-only -- .status.yaml is an INPUT here --
so there is no push step and no write mutex, and activeDeadlineSeconds is
15 minutes rather than the shepherd's two hours.

MCTL_TOKEN is NOT optional here, unlike on the shepherd: the batch read
and the acquire route are both admin-gated, and a bootstrap that cannot
authenticate reads UNKNOWN for every entity and aborts -- safe, but a
wasted run with a confusing report.

The report is JSON on stdout and the shell does not parse it. A grep here
would become a second, drifting copy of the module's own decision
vocabulary.

Refs: mctlhq/.github#57

Claude-Session: https://claude.ai/code/session_01RUQTbQvUQjwbDFd7Nq9bvC
Copilot AI lite review requested due to automatic review settings September 14, 2026 06:54
@claude

claude Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Claude finished @mashkovd's task in 3m 15s —— View job


Review complete

  • Fetch pinned diff (f0d17964...a56233b5)
  • Compare against sibling cwft-mctl-agents-*.yaml templates for consistency
  • Post inline findings
  • Submit verdict

Verdict: Changes requested (1 P1, 1 P2).

The template's own PR description makes a strong case for the parts that matter most here — the dry_run string comparison against the literal "false", the read-only clone, MCTL_TOKEN non-optional — and those are all correctly implemented. The findings are both about scaffolding this template copied from a sibling but didn't fully carry over:

  • P1 — spec.imagePullSecrets is missing. The container pulls ghcr.io/mctlhq/mctl-agents (a private GHCR image), and every other CWFT in this repo that pulls that image (shepherd, implement, investigate, reconcile, run, approve) sets imagePullSecrets: [{name: ghcr-credentials}] at the spec level for exactly that reason. Without it, the pod will hit ImagePullBackOff and the workflow will never execute — a silent no-op for a step whose whole point is a carefully-reviewed dry run.
  • P2 — podMetadata.labels (app.kubernetes.io/name: mctl-agents, mctl.ai/team: admins) is also missing. The shepherd template's own comment explains these exist so agent pods are findable via mctl_get_service_logs in Loki and selectable by NetworkPolicy apart from other workflow pods in the shared argo-workflows namespace — worth keeping given this template is explicitly derived from that scaffolding.

Both are inline on line 54 of wft-lifecycle-bootstrap.yaml (the spec: block), with a Fix-this link on the P1.

argo lint --offline passing doesn't catch either of these since both are semantically valid YAML — they only surface at pod-scheduling time.

secondsAfterFailure: 86400
secondsAfterCompletion: 3600
entrypoint: bootstrap
serviceAccountName: argo-workflow-sa

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: missing imagePullSecrets: [{name: ghcr-credentials}] at the spec level. The main container pulls ghcr.io/mctlhq/mctl-agents (line 68), which is a private GHCR image — every other consumer of this image in this repo (cwft-mctl-agents-shepherd.yaml, -implement, -investigate, -reconcile, -run, -approve) sets this same imagePullSecrets entry at spec: for exactly that reason. Without it, the main container pod will hit ImagePullBackOff and this migration step will never actually execute — a silent no-op for what's meant to be a carefully-reviewed, one-shot ownership import.

Fix this →

secondsAfterFailure: 86400
secondsAfterCompletion: 3600
entrypoint: bootstrap
serviceAccountName: argo-workflow-sa

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: missing podMetadata.labels (app.kubernetes.io/name: mctl-agents, mctl.ai/team: admins) that every sibling agent CWFT sets at this same spot (see cwft-mctl-agents-shepherd.yaml). Per that template's own comment, these labels are what let mctl_get_service_logs find agent pods in Loki during an incident and let NetworkPolicy select agent pods apart from other workflow pods sharing the argo-workflows namespace. Since this template is explicitly a copy of the shepherd's scaffolding, this looks like an unintentional drop rather than a deliberate choice — worth adding for log discoverability on a template whose whole point is to be reviewed row-by-row after the fact.

@claude claude Bot 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.

Has P1/P2 findings, changes requested: 1 P1, 1 P2. The new ClusterWorkflowTemplate is missing spec.imagePullSecrets: [{name: ghcr-credentials}], which every other template pulling ghcr.io/mctlhq/mctl-agents in this repo sets — without it the main container will ImagePullBackOff and the workflow never runs (P1). It also drops the podMetadata.labels block the shepherd template it's copied from uses for Loki log discoverability / pod selection (P2).

Copilot AI 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.

🟡 Changes recommended

Unresolved runtime, image-pull, output-format, and template-resolution issues block approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a manually triggered, one-shot Argo workflow to bootstrap lifecycle ownership records before the observe soak.

Changes:

  • Adds safe-by-default dry-run and explicit apply modes.
  • Clones GitOps state and invokes the lifecycle bootstrap module.
  • Configures credentials, SSH verification, resources, and cleanup TTLs.
File summaries
File Description Final findings
platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml Defines the lifecycle ownership bootstrap workflow. Critical (3 votes): Default image lacks the bootstrap module.
Critical (1 vote): Missing ghcr-credentials may cause ImagePullBackOff.
Moderate (1 vote): Status messages invalidate JSON-only stdout.
Critical (1 vote): Literal template braces may fail Argo template resolution.
Review details

Suppressed comments (1)

platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml:146

  • These status messages go to stdout immediately before the module's JSON output, so the workflow log's stdout is not a valid JSON report despite the contract documented above and the comment at lines 148-150. Send the human-readable notices to stderr so stdout remains exclusively the JSON report.
              echo "▶ APPLY mode: planned rows WILL be written"
            else
              echo "▶ dry run: nothing will be written"
  • Files reviewed: 1/1 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +53 to +54
entrypoint: bootstrap
serviceAccountName: argo-workflow-sa
# --apply to write anything, so an operator who submits this template
# with no parameters at all gets a report and no writes.
- name: agent_image
value: ghcr.io/mctlhq/mctl-agents:1.45.0
- |
set -eu
# The parameter reaches the shell as an ENV VAR, never interpolated
# into the script body: {{workflow.parameters.*}} inside a script is
…Loki

ghcr.io/mctlhq/mctl-agents is private. Without imagePullSecrets the main
container ImagePullBackOffs and the workflow never runs -- every other
template pulling that image carries the same block, and this one dropped
it along with the SDK scaffolding it does not need.

podMetadata comes back for the same reason it exists on the shepherd:
Promtail maps those labels onto Loki's `app` and `team`, and an Argo pod
without them cannot be found through mctl_get_service_logs. This
workflow's entire output is a JSON report on stdout, so a run whose logs
nobody can read produced nothing.

Refs: mctlhq/.github#57

Claude-Session: https://claude.ai/code/session_01RUQTbQvUQjwbDFd7Nq9bvC

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a56233b519

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

secondsAfterFailure: 86400
secondsAfterCompletion: 3600
entrypoint: bootstrap
serviceAccountName: argo-workflow-sa

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add the GHCR pull secret

When this workflow is submitted, the bootstrap pod cannot pull the private ghcr.io/mctlhq/mctl-agents image because the template does not set imagePullSecrets, and argo-workflow-sa has no pull secret attached. Every existing mctl-agents ClusterWorkflowTemplate explicitly references ghcr-credentials; add the same reference here so both dry-run and apply executions can start.

Useful? React with 👍 / 👎.

Comment on lines +67 to +68
- name: agent_image
value: ghcr.io/mctlhq/mctl-agents:1.45.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pin an image that contains the bootstrap module

The default 1.45.0 image does not contain orchestrator.lifecycle.bootstrap (as the commit description itself notes), so the documented submission command, which only passes dry_run, exits with a module-not-found error even after the image-pull credentials are fixed. Pin the first release containing the module before publishing this workflow, especially because the existing mctl-agents release bump glob only covers cwft-mctl-agents-*.yaml and therefore will not update this wft-* file automatically.

Useful? React with 👍 / 👎.

@claude

claude Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Claude finished @mashkovd's task in 4m 48s —— View job


Review complete

  • Fetch pinned diff (f0d17964...773c8431)
  • Review new commit against prior findings (imagePullSecrets, podMetadata.labels)
  • Check remaining findings from other reviewers (image default, stdout JSON contract, template braces)
  • Post inline findings
  • Submit verdict

Verdict: Changes requested (1 P1, 1 P2, 1 P3).

The fix commit (773c8431) correctly resolves both prior findings — imagePullSecrets: [{name: ghcr-credentials}] and podMetadata.labels now match cwft-mctl-agents-shepherd.yaml exactly, placement and all.

Reviewing the rest of the (unchanged) file turned up two new issues:

  • P1 (line 146) — the comment contains the literal tag {{workflow.parameters.*}} inside the same container.args script block where {{workflow.parameters.dry_run}} (168) and {{workflow.parameters.agent_image}} (137) are genuinely substituted. * isn't a defined parameter, and Argo's non-lint substitution pass is expected to error on tags it can't resolve rather than leave them in place. The sibling shepherd template makes the identical documentation point but deliberately writes it as plain backticked text with no braces — this file's version reintroduces the exact pattern the sibling avoids. argo lint --offline passing isn't strong counter-evidence: lint's variable check runs in a permissive mode to tolerate runtime-only variables, and per the PR body this template has only been linted, never actually submitted.
  • P2 (lines 157/159) — the echo "▶ ..." status lines write to stdout ahead of the script's own documented contract two lines below ("It is JSON on stdout for an operator and for the workflow log"). Redirecting them to stderr would keep stdout exclusively the JSON report.
  • P3 (line 81, non-blocking) — the default agent_image (1.45.0) is already acknowledged in the PR description as unable to run this module; noted as a nice-to-have to bump once the release exists, so the safe/no-override path is also the one that works.

- |
set -eu
# The parameter reaches the shell as an ENV VAR, never interpolated
# into the script body: {{workflow.parameters.*}} inside a script is

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: this comment contains the literal tag {{workflow.parameters.*}}, inside the same container.args script block where {{workflow.parameters.dry_run}} (line 168) and {{workflow.parameters.agent_image}} (line 137) are genuinely substituted. Argo's parameter substitution pass runs over the whole args string and looks up every {{workflow.parameters.X}} tag it finds in the defined-parameters map; * is not a parameter name, so this tag can't resolve, and Argo's normal (non-lint) substitution mode errors on unresolved tags rather than leaving them in place — this is the same class of error commonly seen as failed to resolve {{workflow.parameters.X}}.

The sibling cwft-mctl-agents-shepherd.yaml makes exactly this same point in an equivalent comment but writes it as plain backticked text (workflow.parameters.*, no braces) — deliberately avoiding the literal {{ }} syntax for this reason.

argo lint --offline passing here isn't strong evidence against this: lint's variable-resolution check runs in a permissive/allow-unresolved mode to tolerate runtime-only variables, which differs from what the controller does at actual submit/execution time — and per the PR description this template has only been linted, never submitted. If this tag errors at submission, the whole bootstrap container script fails to resolve and the workflow can't run at all.

Fix this →

APPLY=""
if [ "${WORKFLOW_DRY_RUN}" = "false" ]; then
APPLY="--apply"
echo "▶ APPLY mode: planned rows WILL be written"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: the echo "▶ APPLY mode..." / echo "▶ dry run..." lines write to stdout before exec python -m orchestrator.lifecycle.bootstrap runs, ahead of its JSON output. That contradicts the contract this same script documents two lines below (155-163 area): "It is JSON on stdout for an operator and for the workflow log." An operator or tooling reading the workflow log as JSON (e.g. argo logs <wf> | jq .) gets a leading non-JSON line and has to know to strip it first — easy to miss on the one workflow whose entire point is a row-by-row report review before a write-mode run. Redirect these two status lines to stderr (echo "..." >&2) so stdout stays exclusively the JSON report, matching the documented contract.

# --apply to write anything, so an operator who submits this template
# with no parameters at all gets a report and no writes.
- name: agent_image
value: ghcr.io/mctlhq/mctl-agents:1.45.0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: agent_image defaults to 1.45.0, which the PR description itself says does not contain orchestrator/lifecycle/bootstrap.py — the template is only runnable today via an explicit -p agent_image=... override. That's a reasonable stopgap for a template that's "inert until submitted," but nothing in the template enforces it, so an operator who forgets the override gets a ModuleNotFoundError deep in a workflow log rather than a clear signal. Worth a follow-up to bump the default once the release that bundles E1 exists, so the safe path (submit with no overrides) is also the one that actually runs.

@claude claude Bot 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.

Has P1/P2 findings, changes requested: 1 P1, 1 P2, 1 P3. The two prior findings (missing imagePullSecrets, missing podMetadata.labels) are correctly fixed in this commit — both now match the shepherd CWFT exactly. New findings on the unchanged parts of the file: (P1) the comment at line 146 contains the literal tag {{workflow.parameters.*}} inside the same container.args script block where real {{workflow.parameters.X}} substitutions happen; * isn't a defined parameter, and unlike argo lint's permissive resolution mode, the controller's substitution pass at actual submit time is expected to error on unresolved tags — the sibling shepherd template makes the identical point in a comment but deliberately avoids the literal braces. This template has only been linted, never submitted, so the risk is unverified either way. (P2) the two echo status lines at 157/159 write to stdout ahead of the script's own documented JSON-only report contract. (P3, non-blocking) the default agent_image is acknowledged in the PR description as unable to run this module.

The comment warning about parameter tags contained a literal one. The
controller's substitution pass runs over the whole args block, comments
included, and a tag it cannot resolve fails the submission -- so the
comment written to warn about tags would have been the thing that broke
the template. `argo lint` resolves permissively and says nothing about
it, which is why this survived a clean lint. The shepherd CWFT makes the
same point without the braces.

The two progress lines move to stderr. stdout carries the JSON report,
and the fewer things share it the better -- _discover_refs already prints
a skip notice there for every service the shepherd does not own.

Refs: mctlhq/.github#57

Claude-Session: https://claude.ai/code/session_01RUQTbQvUQjwbDFd7Nq9bvC
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@claude

claude Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Claude finished @mashkovd's task in 1m 12s —— View job


Review complete

  • Fetch pinned diff (f0d17964...5c09a369)
  • Review new commit against prior findings (unresolvable template tag, stdout JSON contract)
  • Check remaining findings from other reviewers (agent_image default)
  • Submit verdict

Verdict: Approved (0 P1/P2, 1 P3 pre-existing/non-blocking).

Commit 5c09a369 cleanly resolves both outstanding findings from the previous review pass, and doesn't touch anything else:

  • P1 (fixed) — the comment at line 145-148 no longer contains the literal {{workflow.parameters.*}} tag. It now reads "an Argo parameter tag inside a script" and adds an explicit note explaining why the braces were dropped (the controller's substitution pass runs over the whole args block, comments included, and an unresolvable tag fails the submission) — matching the sibling shepherd template's approach exactly.
  • P2 (fixed) — both echo "▶ ..." status lines (163, 172 in the current file) are now redirected to stderr (>&2), with a comment explaining the reasoning (stdout is reserved for the JSON report, which is already not the only stdout content thanks to _discover_refs's skip notices, so nothing further should be added to it). Stdout is now exclusively the JSON report as documented two lines below.
  • P3 (unchanged, non-blocking) — agent_image still defaults to 1.45.0, which the PR description itself acknowledges lacks orchestrator/lifecycle/bootstrap.py. This was already flagged as a pre-submission checklist item in the PR body rather than a template defect, so it doesn't block merge — just don't submit without -p agent_image=... (or a bumped default) until that release exists.

imagePullSecrets and podMetadata.labels (fixed in 773c8431) remain correctly in place and unaffected by this commit.

No further changes requested.

@claude claude Bot 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.

No P1/P2 findings (1 P3, pre-existing). Both prior blockers (unresolvable {{workflow.parameters.*}} tag in the args comment, stdout echoes ahead of the JSON report) are fixed in this commit, matching the shepherd CWFT's conventions exactly. Good to merge.

… run it

Three reviewers made the same point and they are right: agent_image
defaulted to today's pin, which does not contain
orchestrator/lifecycle/bootstrap.py. The documented submission -- the one
with no parameters -- would have failed inside the container on a missing
module, which is a confusing way to learn the image is wrong.

There is no value that could go here and work, because the module is not
in any released image yet. So the parameter carries no default and Argo
refuses the submission by name instead: "parameter agent_image was not
supplied". A template that cannot run with its own defaults should say so
at submit time, not at runtime.

Give it a default once a release carries the module.

Refs: mctlhq/.github#57

Claude-Session: https://claude.ai/code/session_01RUQTbQvUQjwbDFd7Nq9bvC
@mashkovd

Copy link
Copy Markdown
Member Author

The agent_image point was raised by all three reviewers and it stands on its own — acknowledging it in the PR body was not a fix.

There is no value that could go there and work: orchestrator/lifecycle/bootstrap.py is not in any released image yet. So the parameter now has no default and Argo refuses the submission by name — parameter agent_image was not supplied — rather than the documented no-parameter submission failing inside the container on a missing module. The description and the submit example say so too.

The imagePullSecrets and podMetadata comments still showing on this head are re-anchored from a56233b5; both landed in 773c8431.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@claude

claude Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Claude finished @mashkovd's task in 2m 7s —— View job


I'll analyze this and get back to you.

@claude claude Bot 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.

No P1/P2 findings (0 P3). This commit only removes the agent_image default (so a submission with no override now fails fast by name instead of hitting ModuleNotFoundError inside the container) and adds explanatory comments — a config-only change equivalent to an image-tag adjustment. All prior P1/P2 findings (imagePullSecrets, podMetadata.labels, unresolvable {{workflow.parameters.*}} tag, stdout JSON contract) remain fixed and unaffected. Good to merge.

@mashkovd
mashkovd merged commit 482afbe into main Sep 14, 2026
20 checks passed
@mashkovd
mashkovd deleted the feat/lifecycle-bootstrap-workflow branch September 14, 2026 07:12
@github-actions

Copy link
Copy Markdown
Contributor

Antigravity (agy) review — informational

Model: gemini-3.8-flash-medium · commit a56233b.

Finding 1 (P2)

  • File: platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml (approx. line 89)
  • Anchor: + apk add --no-cache openssh-client ca-certificates
  • Concrete failure scenario: The clone-gitops init container runs apk add --no-cache openssh-client ca-certificates dynamically on every execution. In secured Kubernetes clusters where egress traffic is restricted by NetworkPolicies or firewall rules to specific whitelisted endpoints (such as ssh.github.com:443), outbound HTTP/HTTPS connections to Alpine Linux mirror repositories (dl-cdn.alpinelinux.org) will time out or be blocked. Because set -e is set at line 88, this network failure causes the init container to terminate with a non-zero exit code (Init:Error / Init:CrashLoopBackOff), preventing the workflow from ever running. In addition, the base image alpine/git:2.43.0 already includes openssh-client and ca-certificates out of the box, making this external runtime dependency both redundant and fragile.
  • Proposed fix: Remove the apk add invocation from the init container's script:
              args:
                - |
                  set -e
                  mkdir -p ~/.ssh
                  cp /secrets/deploy-key/ssh-privatekey ~/.ssh/id_ed25519

Finding 2 (P3)

  • File: platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml (approx. line 1)
  • Anchor: +apiVersion: argoproj.io/v1alpha1
  • Concrete failure scenario: There is no test visible in this diff validating the newly introduced lifecycle-bootstrap ClusterWorkflowTemplate (such as manifest validation via argo lint, parameter verification, or dry-run execution checks under tests/).
  • Proposed fix: Add a test under tests/ verifying that wft-lifecycle-bootstrap.yaml passes argo lint and that parameter defaulting and workflow structure conform to expected template specifications.

@github-actions

Copy link
Copy Markdown
Contributor

Antigravity (agy) review — informational

Model: gemini-3.8-flash-medium · commit a298db2.

Findings

Finding 1

  • Severity: P3
  • File & Line: platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml:1
  • Anchor: +apiVersion: argoproj.io/v1alpha1
  • Concrete Failure Scenario: A new ClusterWorkflowTemplate (lifecycle-bootstrap) is introduced to perform lifecycle ownership migration, but there is no test visible in this diff under tests/ verifying schema validation or template linting (e.g., via argo lint or kubeconform). If template structure or parameter mappings regress in future updates, syntax or schema errors may only be discovered when an operator attempts to submit the template in production.
  • Proposed Fix: Add a test under tests/ (e.g., in workflow template validation or CI lint suites) to lint and validate platform-gitops/argo-workflows/cluster-templates/wft-lifecycle-bootstrap.yaml against the Argo Workflows CRD schema.

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