Skip to content

feat(provenance): ankra application provenance and ankra org provenance (ankra-q573dh.44) - #505

Open
Myothas wants to merge 5 commits into
masterfrom
ankra-q573dh.44-provenance-cli
Open

Myothas wants to merge 5 commits into
masterfrom
ankra-q573dh.44-provenance-cli

Conversation

@Myothas

@Myothas Myothas commented Oct 14, 2026

Copy link
Copy Markdown
Member

What

CLI surfaces for verified provenance at deploy (cluster#4611):

  • ankra application provenance get|set|verify <app>: effective mode and its source, set --mode off|warn|enforce or --clear, and a dry-run verify --image <ref>... that exits 1 when a deploy would be refused.
  • ankra org provenance get|set|keys|rotate|revoke: organisation default, signing keys (keys --public-keys prints PEM for cosign verify-attestation).
  • Under enforce every command that shows or turns it on says older un-attested versions cannot be deployed or rolled back to, and the exact command to switch to warn. Enabling enforce and revoking a key confirm first (--yes).
  • Writes need security.manage (exit 7 without it); an older platform's bare 404 is named; the stored mode is compared with the request.

Tests

18 new tests against an httptest platform (method, path, body), including -o json stdout cleanliness, declined prompts sending nothing, and usage errors. Mutation check: breaking mode validation fails 5+ tests; restored. Full go test ./... and golangci-lint pass in the pre-commit hook.

CHANGELOG entry under Unreleased.

Bead: ankra-q573dh.44

🤖 Generated with Claude Code

…ra org provenance (ankra-q573dh.44)

Drives the verified-provenance routes from cluster#4611: the per-application
mode, the organisation default, the dry-run verify, and the signing keys
(list, rotate, revoke). Every place that shows or turns on enforce says that
versions published before the first attested publish cannot be deployed or
rolled back to, and how to switch to warn. Turning enforce on and revoking a
key ask first.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ankra-platform

ankra-platform Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Ankra AI review

Verdict: comments.

Well-structured addition of provenance policy and key-management commands with thorough tests, confirmation prompts on destructive actions, and careful handling of unknown-vs-refused verification states. No clear defects in the diff itself; two findings depend on helpers defined outside the diff. CI is still running, so build status is unknown.

Findings

  • [low] confirmPrompt behaviour on non-interactive stdin is unverified (cmd/application_provenance.go:135)
    Turning on enforce (and revoking a key) relies on confirmPrompt failing closed when stdin is not interactive and --yes was not passed (e.g. in a CI script). confirmPrompt is not shown in this diff; if it treats EOF as 'yes' or blocks forever, a script could either hang or silently enable enforce. Please confirm it returns a cancellation error on EOF/no input.

Reviewed commit c1f6de0. This review is read-only and advisory.

Comment thread cmd/org_provenance.go Outdated

func printOrganisationProvenancePolicy(out io.Writer, policy *client.OrganisationProvenancePolicy) {
_, _ = fmt.Fprintf(out, " Organisation default: %s\n", provenanceModeLabel(policy.Mode,
"not set (applications use Ankra's default: off for applications created before 2026-10-14, warn since)"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] Hardcoded platform-default date in user-facing output

The 'not set' fallback text hardcodes Ankra's default ('off for applications created before 2026-10-14, warn since'). This is a hardcoded claim about server-side behaviour that will silently go stale if the platform default or cutoff changes, and users will trust it as a current observation. Consider having the API return the effective default (or its description) so the CLI reports what the platform actually does rather than what it did when this string was written.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in the next push: the fallback text no longer states the platform's default date.

Comment thread cmd/provenance_common.go
return withExitCode(exitNotFound, fmt.Errorf("%s: %w", operation, apiError))
}
}
if hasStatus && unexpected.StatusCode == http.StatusServiceUnavailable {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] 503 error message names keys even for policy operations

The 503 branch always says 'the provenance keys could not be read right now', but provenanceError is also used for policy reads, policy writes, verify, rotate and revoke. A 503 during 'org provenance set' would tell the user the keys could not be read, which misdescribes what failed. Use the operation string (already passed in) to describe the failure, or reserve the keys wording for the keys/rotate/revoke call sites.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in the next push: the 503 message now uses the operation string and no longer names keys.

Comment thread cmd/provenance_common.go
}
if hasStatus && unexpected.StatusCode == http.StatusNotFound {
switch unexpected.Detail {
case "", routeAbsentDetail:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] Undefined symbols routeAbsentDetail and UnexpectedResponseError.Detail

This relies on routeAbsentDetail and on UnexpectedResponseError having a Detail field, neither of which is shown in the diff. If Detail is not populated for router 404s (e.g. only set for JSON error bodies), the old-platform detection could misfire: a bare 404 with an empty or unparsed body would be reported as 'platform does not offer provenance' even when the route exists but the application id was wrong. Confirm the router's 404 body shape matches the routeAbsentDetail constant.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Both exist in the repo, outside the diff: routeAbsentDetail = "Not Found" in cmd/targets.go (the router's own 404 body) and UnexpectedResponseError.Detail in internal/client/unexpected_response.go, which is set only when the backend sent a JSON detail. A handler's 404 (unknown application or key) carries its own sentence, so it exits 3 and is not reported as an old platform; only an empty or "Not Found" detail is. The same mapping is used by control-plane-heal and hosted logs, and TestApplicationProvenanceOldPlatformIsNamed pins it.

prompt := fmt.Sprintf("Turn enforce on for %q? Deploys are then refused unless every image is attested, and "+
"versions published before the first attested publish cannot be deployed or rolled back to "+
"(switch to warn to lift that). [y/N]: ", arguments[0])
if confirmError := confirmPrompt(command.InOrStdin(), command.OutOrStdout(), prompt, yes); confirmError != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] confirmPrompt and resolveApplicationArgument signatures assumed

confirmPrompt is called as (io.Reader, io.Writer, string, bool) and resolveApplicationArgument as (command, arguments); neither is defined in the diff. If confirmPrompt does not treat EOF on stdin as a decline, a non-interactive run without --yes could block or behave unexpectedly on the enforce path. Verify the helper declines (rather than errors or hangs) when stdin is closed.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

confirmPrompt (cmd/cluster_partial.go:697) reads one line; on EOF the line is empty, which is not y/yes, so it returns errCancelled (exit 4) rather than blocking or proceeding. Closed stdin without --yes therefore declines. TestApplicationProvenanceSetEnforceAsksFirst covers a declined prompt sending nothing.

… the operation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Comment thread cmd/provenance_common.go
}
if hasStatus && unexpected.StatusCode == http.StatusNotFound {
switch unexpected.Detail {
case "", routeAbsentDetail:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] Referenced symbols not visible in the diff

provenanceError relies on routeAbsentDetail, client.PermissionDeniedError, and client.UnexpectedResponseError (with a Detail field), and the command files rely on confirmPrompt, resolveApplicationArgument, renderStructured, structuredFormatFromFlags, registerStructuredOutputFlags, withExitCode, and the exit* constants, none of which are declared in this diff. If any of these do not exist with the assumed shapes (e.g. UnexpectedResponseError lacking a Detail string, or routeAbsentDetail not matching the router's 404 body), the package will not compile or the old-platform 404 branch will never trigger. I could not see their declarations, so please confirm they exist as assumed.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Same answer as the earlier thread: all of these helpers already exist in the repo outside the diff (cmd/targets.go routeAbsentDetail, cmd/cluster_partial.go confirmPrompt, cmd/output.go, cmd/exitcodes.go) and the package compiles and passes tests and lint in CI.

Comment thread cmd/org_provenance.go
return renderError
}
out := command.OutOrStdout()
if onlyPEM, _ := command.Flags().GetBool("public-keys"); onlyPEM {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] --public-keys prints nothing when no keys exist

When the organisation has no keys, the table path prints a helpful 'No provenance key exists yet' message, but the --public-keys path silently prints nothing and exits 0. A script doing keys --public-keys > provenance.pub then feeds an empty file to cosign with no hint why. Consider writing the same note to stderr when the list is empty so the empty stdout stays machine-consumable but the user is not left guessing.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed: with no keys, --public-keys now writes the same note to stderr (stdout stays empty, exit 0).

…resolve it

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
prompt := fmt.Sprintf("Turn enforce on for %q? Deploys are then refused unless every image is attested, and "+
"versions published before the first attested publish cannot be deployed or rolled back to "+
"(switch to warn to lift that). [y/N]: ", arguments[0])
if confirmError := confirmPrompt(command.InOrStdin(), command.OutOrStdout(), prompt, yes); confirmError != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] confirmPrompt behaviour on non-interactive stdin is unverified

Turning on enforce (and revoking a key) relies on confirmPrompt failing closed when stdin is not interactive and --yes was not passed (e.g. in a CI script). confirmPrompt is not shown in this diff; if it treats EOF as 'yes' or blocks forever, a script could either hang or silently enable enforce. Please confirm it returns a cancellation error on EOF/no input.

Ankra AI review. Read-only and advisory.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

confirmPrompt (cmd/cluster_partial.go:697) treats anything but y/yes, including EOF, as errCancelled (exit 4). It cannot hang on closed stdin and cannot default to yes. TestApplicationProvenanceSetEnforceAsksFirst and TestOrgProvenanceRevokeConfirmsAndSendsReason pin the decline path.

Myothas and others added 2 commits October 14, 2026 17:13
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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