Skip to content

[Fleet incident] Detect and disable orphaned one-shot GitHub workflows #929

Description

@seonghobae

Live fleet finding

The GitHub Actions workflow registry currently reports 42 active workflows for ContextualWisdomLab/appguardrail, including multiple temporary one-shot identities such as:

  • apply-dashboard-pluralization-once.yml;
  • finalize-opencode-commercial-loop-once.yml;
  • harden-opencode-commercial-loop-once.yml through harden-opencode-commercial-loop-v6-once.yml;
  • apply-pinned-https-integration-once.yml;
  • harden-pinned-https-cli-once.yml.

Fresh contents-API reads against the current default branch develop return 404 Not Found for sampled paths including finalize-opencode-commercial-loop-once.yml, apply-dashboard-pluralization-once.yml, and harden-opencode-commercial-loop-v6-once.yml. The source files were removed, but their GitHub Actions registry entries still report state: active.

The current scheduled Commercial Readiness Loop itself is healthy: protected-default-branch run 31586926814 completed and correctly stopped with action=wait-prs for the live PR queue. This issue is therefore not a request to change that production loop.

Root cause

Temporary writer workflows were removed from Git history after use, but workflow lifecycle cleanup treated source deletion as sufficient. GitHub retains workflow registry identities independently; source removal did not disable the registered workflow records. Existing repository tests focus on file contents and cannot detect an orphan identity whose file is no longer present.

This creates:

  • misleading active automation inventory;
  • audit and incident-response ambiguity about which writers remain enabled;
  • unnecessary attack-surface and policy noise;
  • failure of the fleet invariant that no temporary write-capable/self-modifying repair workflow remains;
  • a detection gap in AppGuardrail itself: the repository currently cannot report this same-class issue from live GitHub workflow metadata.

Realistic remediation

Do not recreate or self-delete the old workflow files merely to clean them up. Use the GitHub Actions workflow lifecycle API from an authorized operator/normal governance path to disable each orphaned registry identity after proving its file is absent from the current protected default branch.

Because AppGuardrail's own policy says its repository issues must be detectable by AppGuardrail, add a read-only scanner/control-plane rule that:

  1. paginates the live Actions workflow inventory;
  2. resolves the current protected default-branch tree;
  3. classifies every workflow record as present, orphaned-deleted, disabled, or unresolved;
  4. flags active orphan records, especially names/paths indicating once, apply, finalize, repair, bootstrap, or branch-writing behavior;
  5. never treats a missing contents response, pagination failure, or permission failure as a clean result;
  6. emits exact workflow ID, path, state, current default-branch SHA, and evidence timestamp;
  7. proposes disablement but does not mutate workflow state from an untrusted scan job.

Acceptance criteria

  • complete paginated inventory, not a sampled list;
  • all active registry paths absent from the current protected default branch are reviewed and either disabled or explicitly justified;
  • no production scheduled/reusable workflow is disabled merely because a historical commit contained a different path;
  • no temporary write-capable/self-modifying workflow source is reintroduced;
  • AppGuardrail gains executable detection coverage for active-orphan workflow identities;
  • adversarial tests cover truncated pagination, transient 404/403/5xx, default-branch movement, path case differences, a disabled orphan, and a live file whose name contains once but has an explicit supported contract;
  • exact-head CI/security/review gates succeed;
  • normal protected-default-branch integration;
  • a post-integration live inventory shows every former orphan identity disabled and the production Commercial Readiness Loop still scheduled and operational.

This is part of the organization-wide GitHub Actions fleet incident. The AppGuardrail dedicated writer loop owns implementation; the fleet audit remains read-only and tracks the live registry to closure.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: securitySecurity boundary, hardening, or vulnerability preventionpriority: mediumNormal-priority or P2 workscope: commercial-readinessProduction, enterprise, release, or commercial readinessstatus: triagedOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capability

    Type

    No type

    Projects

    • Status
      Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions