Skip to content

publish-plan-task: the actor allowlist fails silently if the App identity changes #354

Description

@ptr727

Problem

publish-plan-task.yml decides the release gate for a push by string-matching the actor against an allowlist:

if [[ "$REF" == "main" ]] && { [[ "$ACTOR" == "ptr727-codegen[bot]" ]] || [[ "$ACTOR" == "dependabot[bot]" ]]; }; then
  publish=true
fi

The allowlist is correct today - verified on ptr727/ESPHome-NonRoot, where every push-triggered publish run carries actor=ptr727-codegen[bot].

The concern is the failure mode, not the current value. If the App is ever renamed, replaced, or its installation reissued under a different slug, the comparison silently evaluates false, publish=false, and the publish job is skipped. Nothing errors, no annotation is emitted, and the run is green. Releases simply stop happening on pin pushes.

It is worse than a normal silent failure because the weekly schedule keeps publishing, so main still produces releases and the symptom is only a loss of timeliness - a new upstream version waits up to seven days instead of landing the same day. That is easy to miss for a long time, and it defeats the tracker's entire purpose, which is same-day upstream publishing.

The same shape applies to dependabot[bot], though GitHub is unlikely to rename that one.

Recommendation

Two options, cheapest first.

1. Annotate a non-publishing pin push (minimal, recommended). The push trigger is already path-scoped to the pin file, so the only legitimate non-publishing case is a human editing the pin by hand - rare, and worth surfacing anyway. Emit a warning instead of skipping quietly:

push)
  if [[ "$REF" == "main" ]] && { [[ "$ACTOR" == "ptr727-codegen[bot]" ]] || [[ "$ACTOR" == "dependabot[bot]" ]]; }; then
    publish=true
  elif [[ "$REF" == "main" ]]; then
    echo "::warning::Pin push on main by unrecognized actor '$ACTOR'; not publishing. If this is the codegen App under a new identity, update the allowlist in publish-plan-task.yml."
  fi
  ;;

This keeps the gate's behavior identical and costs one line, but the run is visibly annotated rather than silently inert.

2. Resolve the identity instead of hardcoding it. Mint an App token with actions/create-github-app-token and read the App's own slug (GET /app), then compare against that. This removes the hardcoded string entirely, at the cost of a token mint per run and a heavier task. Worth it only if the allowlist proves fragile in practice.

Generalization

The transferable rule for the fleet: an identity allowlist used as a gate should fail loud, not open or closed in silence. A gate that can quietly stop gating - or quietly stop passing - looks identical to a healthy one in the Actions UI, and the tools that would normally catch a regression (status checks, lint) all stay green.

Context

Raised while reviewing ptr727/ESPHome-NonRoot#138, which adopts this task. Filing here because the task is shared, so the fix belongs upstream rather than in one consumer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions