Skip to content

feat(workflow_audit): WF028 — reusable call into a moved repository - #965

Merged
hyperpolymath merged 5 commits into
mainfrom
claude/wf028-moved-repo-reusable
Oct 27, 2026
Merged

hyperpolymath merged 5 commits into
mainfrom
claude/wf028-moved-repo-reusable

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Why

hyperpolymath/standards moved to metadatastician/standards on 2026-10-25. GitHub keeps a redirect for git and the REST API, but it does not follow that redirect when it resolves a reusable workflow's uses:. Every caller still naming the old owner therefore ends in startup_failure ("workflow was not found") before any job runs. This was measured on hypatia's governance runs 40424594888 and 40424740139. #961 proposed a rule for this so that a regression is caught by a rule, not found by people. This PR is that rule.

What

  • WF028 (check_reusable_call_to_moved_repository/1, wired into audit/3) flags a reusable-workflow call by a moved repository's former name. It finds the call where WF027 does: a job's uses: key in block or flow style, a value continued below its key, or a call through a job alias. A path in a run: script, an env: value, a comment or a step's uses: does not fire. The finding names the re-pointed reference at the same revision, since a move keeps history.
  • The moved-repo table is derived from the new StandardsRepo.former/0. Each further transfer into the org (standards ruling D97) is then one row, not a new rule.
  • Like WF026 and WF027, WF028 is advisory, severity low and auto_fixable: false. AGENTIC's must-not-promote-to-blocking rule applies, and no fleet fixer rewrites the owner yet.
  • cli.ex now carries the finding's replacement key through to SARIF and the fleet; until now it was dropped by the Map.take whitelist.
  • AGENTIC [workflow-pin-detection] and Operations.md list WF028.

Validation

  • test/rules/workflow_audit_pins_test.exs: 104 tests, 0 failures. That includes 9 new WF028 tests and a self-check that hypatia's own .github/workflows produce no WF028 findings. workflow_audit_chapel, workflow_audit_cron_drift and standards_repo tests pass too.
  • Mutation check: with the job-key guard replaced by true, the "step / run-script" test goes red.
  • mix format --check-formatted passes on the touched files.
  • Caveat: these runs used a standalone compile of the rule modules on Elixir 1.14. The session's network policy blocks repo.hex.pm, so the project's deps (and the full mix test, including cli_test.exs) could not be fetched. CI is the first full-suite run.

Follow-ups outside this repo

  • gitbot-fleet: an owner re-point fixer (WF028 → auto_fixable: true), and fix-stale-reusable-pin.sh / stale-reusable-pins.tsv still key on the old path.
  • rsr-oracle.yml still treats hyperpolymath/standards as the canon (separate change).

Generated by Claude Code

hyperpolymath/standards moved to metadatastician/standards on 2026-10-25.
GitHub keeps a redirect for git and the REST API, but does not follow it
when it resolves a reusable workflow's `uses:`, so every caller still
naming the old owner ends in startup_failure before any job runs
(measured: hypatia governance runs 40424594888 / 40424740139).

WF028 flags that call where WF027 finds a reusable call (a job's `uses:`
key in block or flow style, continued below its key, or via a job alias),
and names the re-pointed reference at the same revision. The moved-repo
table is derived from StandardsRepo.former/0, so each further transfer
into the org (standards D97) is a row, not a rule.

Advisory, severity low, auto_fixable: false, like WF026/WF027 (AGENTIC
must-not-promote-to-blocking); no fleet fixer rewrites the owner yet.
cli.ex now carries the finding's `replacement` through to SARIF/fleet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDfvetbJ5z7uREtbJWw
@coderabbitai

coderabbitai Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 3 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 40f2d0e4-645d-4ffe-9755-5eae7afd5968
Commits

Reviewing files that changed from the base of the PR and between 02a5d97 and 9e889c3.

Files selected for processing: 7
  • .machine_readable/descriptiles/AGENTIC.a2ml
  • docs/wiki-pages/Operations.md
  • lib/hypatia/cli.ex
  • lib/rules/pin_sites.ex
  • lib/rules/standards_repo.ex
  • lib/rules/workflow_audit.ex
  • test/rules/workflow_audit_pins_test.exs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@hyperpolymath
hyperpolymath marked this pull request as ready for review October 27, 2026 01:32
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T02:17:16.556729Z 9e889c3 New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copy link
Copy Markdown
Owner Author

Governance, Secret Scanner and Hypatia Security Scan end in startup_failure on this head. That isn't caused by this PR.

The failure happens before any job starts, and it is the same on main (governance runs 40424594888 and 40424740139). The cause is the repo's Actions allow-list: it admits only reusables owned by hyperpolymath, and the callers point at metadatastician/standards/... since #958. This PR doesn't touch any workflow file. No fix exists yet. The fix is the allow-list PUT (remediate.sh B-ALLOWLIST, superset from #961), and the sweep that applies it currently fails with 401 because HYPATIA_DISPATCH_PAT needs rotating. That is an owner action. A re-run would hit the same startup refusal, so I haven't spent one.


Generated by Claude Code

@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: a3e6b3f502

ℹ️ 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".

Comment thread lib/rules/workflow_audit.ex
Comment thread lib/rules/workflow_audit.ex Outdated
Comment thread lib/rules/workflow_audit.ex Outdated
…ases only

Three Codex findings on #965, each with a test that fails on the old code:

- A block-style `uses:` value ends at whitespace or its closing quote, not
  at `,` `}` `]` `#`: a branch or tag may hold them, and the replacement
  claims the same revision. Flow delimiters still end a flow entry.
- A leading `uses:` no longer hides the flow siblings on its line
  (`uses: a@x }, b: { uses: a@y`): both are reported.
- An anchored mapping counts as a reusable call only where a job is given
  it whole (`g: *shared`); `- *shared` under `steps:` is a step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDfvetbJ5z7uREtbJWw
@coderabbitai

coderabbitai Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Add Carrot credits or activate Agent usage billing to use Autofix

@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: 3d2cbf7c2c

ℹ️ 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".

Comment thread lib/rules/workflow_audit.ex Outdated
Comment thread lib/rules/workflow_audit.ex Outdated
…y each alias

Two more Codex findings on #965, fixed at the root rather than per case:

- The `uses:` value is now read as a YAML scalar: a quoted one runs to its
  closing quote whatever it holds (`"…@Release,one"` in a flow job), and
  only a plain one ends at whitespace (block) or the flow delimiters.
- PinSites.node_alias_sites/1 now reports each alias' `kind` (:job or
  :step), decided where the alias stands, by the classification
  node_aliases/4 already made. WF028 keeps only :job, so
  `jobs: { a: *job, b: { steps: [*step] } }` no longer marks the step's
  anchored `uses:` live. The key is additive; existing callers match on
  subsets of the map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDfvetbJ5z7uREtbJWw

@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: 10ab3da81f

ℹ️ 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".

# at whitespace in block style (a branch or tag may hold `,` `}` `]`
# `#`) and, inside a flow collection, at the delimiters too.
key = "[\"']?uses[\"']?\\s*:\\s*(?:[&!]\\S*\\s+)*"
quoted = "\"([^\"]*)\"|'([^']*)'"

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 Decode quoted YAML scalars before matching moved repositories

When a valid double-quoted uses: value contains a YAML escape, the regex compares the encoded source rather than the decoded scalar, so a call such as uses: "\x68yperpolymath/standards/.github/workflows/x.yml@main" resolves to the moved repository but produces no WF028 finding. Decode double-quoted YAML values before applying call_re so escaped owner, path, or ref characters cannot bypass the rule.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Leaving this as is. The path traced is evasion: someone would have to write \x68yperpolymath on purpose. WF028 isn't a security control; it warns a repository that its own call will hit startup_failure, and the failure itself is loud and visible on every run. Nobody has a reason to hide from it. Decoding YAML escapes would also mean writing a scalar decoder the codebase doesn't have, which costs more than this blind spot does.


Generated by Claude Code

# makes a reusable call; `- *step` and `steps: [ *step ]` are steps.
# PinSites classifies each alias where it stands, not by its line.
aliased =
for %{key_line: n, kind: :job} <- Hypatia.Rules.PinSites.node_alias_sites(content),

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 Recognize aliases continued below job keys

When a job's alias value is placed on the following line, as in jobs:\n g:\n *job, valid YAML resolves g to the anchored mapping, but node_alias_sites/1 returns no job entry because it recognizes only the same-line g: *job form. If that external mapping calls the moved repository, aliased remains empty and WF028 omits the failing reusable call; include aliases used as continued job values when collecting live anchor lines.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Leaving this as is. g: with *job on the line below is valid YAML, but the classifier is PinSites.node_aliases/4, which WF027, PinIntegrity and the merge policy also rely on. Teaching it a new layout changes all of them, which is out of proportion for a rare form in an advisory rule. If it's worth doing, it's a PinSites change with its own tests across those callers, not something to ride along on WF028.


Generated by Claude Code

Comment on lines +3103 to +3105
case Map.fetch(continued, number) do
{:ok, {joined, _how}} -> joined
:error -> line

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 Read unindented continuations inside flow jobs

Inside a flow mapping YAML does not use indentation to determine the value, so jobs: {\ng: {\nuses:\nhyperpolymath/standards/.github/workflows/x.yml@main\n}\n} is a valid reusable call. wf_continued_uses/1 applies block-style indentation rules and returns no entry for this layout, leaving the empty uses: line unchanged here and causing WF028 to miss the call; resolve continued values using the active flow context rather than requiring deeper indentation.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Leaving this as is. The layout is valid YAML, but I traced who writes it: nobody does. Estate workflows are block-style, with a few KYAML (flow) jobs that keep the value on its key's line or indent it. The resolver is wf_continued_uses/1, which WF027 shares, so fixing it here would widen a shared helper for a layout with no known caller. WF028 is advisory, so the cost of a miss is one missed hint. If this ever needs fixing, it belongs in the shared resolver for WF027 and WF028 together, not in this PR.


Generated by Claude Code

Comment thread lib/rules/workflow_audit.ex Outdated
…tension

A workflow file name may hold `@` (`build@nightly.yml@release`), so the
reusable's path now ends at `.yml`/`.yaml` rather than at the first `@`;
`reusable` and `current_sha` are reported as GitHub reads them (Codex, #965).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4QvDfvetbJ5z7uREtbJWw

@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: e7db2dc499

ℹ️ 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".

key = "[\"']?uses[\"']?\\s*:\\s*(?:[&!]\\S*\\s+)*"
quoted = "\"([^\"]*)\"|'([^']*)'"
block_value = "(?:" <> quoted <> "|([^\\s\"']+))"
flow_value = "(?:" <> quoted <> "|([^\\s\"'#,}\\]]+))"

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 Preserve hashes inside unquoted flow references

In an unquoted flow scalar, # starts a YAML comment only when preceded by whitespace, and Git permits it in branch/tag names. For jobs: { g: { uses: hyperpolymath/standards/.github/workflows/x.yml@release#one } }, this character class truncates the parsed ref to release, so WF028 emits incorrect current_sha and replacement metadata instead of preserving release#one; allow # in the plain value while continuing to stop at whitespace.

Useful? React with 👍 / 👎.

inline_re
|> Regex.scan(line, return: :index)
|> Enum.flat_map(fn [{at, _} | groups] ->
if wf027_inline_job?(lines, flow, line, number, at + 1) or live?,

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 Track live anchored uses sites rather than whole lines

When multiple anchored mappings are defined on one physical line, aliased contains only their shared key_line, so a job alias makes live? true for every inline uses: match on that line. For example, if &job contains a current-repository call and &step contains the moved-repository call on the same line, with *job used as a job and *step used only under steps:, this branch reports the step-level call even though WF028 excludes actions; retain the specific anchored site offset or identity instead of marking the entire line live.

Useful? React with 👍 / 👎.

@hyperpolymath
hyperpolymath merged commit eadb38c into main Oct 27, 2026
48 checks passed
@hyperpolymath
hyperpolymath deleted the claude/wf028-moved-repo-reusable branch October 27, 2026 02:13
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