STAC-25540: keep the private-index credential off the pull request path - #365
Merged
LouisParkin merged 1 commit intoAug 5, 2026
Conversation
The previous revision confined the GitLab package registry credential to a
single step and claimed that reaching it would require editing the workflow.
That claim was wrong. A `pull_request` run executes the pull request's own copy
of the workflow *and* of every script it calls, so a pull request could rewrite
fetch_private_wheels.sh, reorder the steps, or add one of its own. Confining a
secret inside pull-request-controlled code is hardening, not a boundary.
So the private-index suites no longer run on pull requests at all. They run on
push, tag and workflow_dispatch events, whose contents are reviewed before they
reach the release branch, and where the secret is therefore not exposed to
unreviewed code.
* select-checks.sh moves private-index suites to a new
`deferred_private_checks` output on pull requests, so the matrix is empty
rather than gated, and the reason is reported.
* check-tests-private-index is conditioned on the event, replacing the fork
guard that is now redundant.
* fetch_private_wheels.sh refuses to run on a pull_request event, so the rule
survives an edit to the workflow condition.
* ci-success reports the deferral, so a green pull request never implies
vsphere was covered when it was not.
The cost is that vsphere is verified on the release branch rather than on the
pull request that changes it. That is accepted knowingly: the suite changes a
handful of times a year, and the alternatives cost more than they return. The
durable fix is to stop needing the private index -- VMware now publishes this
SDK to public PyPI under renamed packages -- which deletes the credential, the
job and this gap together.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Author
CI evidence — run 31014217891: 18 success, 1 skippedThe skip is the point, and it is the right skip: So on this pull request:
That last part is what stops this becoming a silent regression: Local verification
The one thing this run cannot demonstrate is the push path, since that only fires once this lands on |
LouisParkin
merged commit Aug 5, 2026
d092b06
into
STAC-25463-integrations-github-ci
19 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to @LouisLotter's second-pass review comment on #362 (
checks-tests.yml:389). He was right, and my reply in the workflow was wrong.What I got wrong
The merged revision (#364) confined the GitLab package registry credential to a single step and stated that reaching it "would require editing this workflow". That was inaccurate, and it understated the problem in two ways:
.setup-scripts/fetch_private_wheels.shis itself checked out from the pull request head. A PR can edit the script that holds the credential — no workflow edit needed.source .setup-scripts/setup_env.shruns as root, in the container, before the credential step. It can overwrite the system interpreter outright, defeating the workspace-interpreter guard that made "system python" look like a guarantee.More fundamentally: a
pull_requestrun executes the pull request's own copy of the workflow and every script it calls. Repository secrets plus PR-controlled code cannot be arranged into a security boundary, however carefully the code in between is written. The reviewer's wording was precise on exactly this point.What this changes
The private-index suites no longer run on pull requests at all. They run on
push, tag andworkflow_dispatchevents, whose contents are reviewed before reaching the release branch.select-checks.shmoves private-index suites to a newdeferred_private_checksoutput on pull requests, so the matrix is simply empty rather than gated.check-tests-private-indexis conditioned on the event; the fork guard is now redundant and removed.fetch_private_wheels.shrefuses to run on apull_requestevent, so the rule survives an edit to the workflow condition rather than depending on it.ci-successreports the deferral, so a green PR never implies vsphere was covered when it was not.The single-step credential handling from #364 is kept. It is genuine hardening — it keeps the password away from the suite's dependency tree, which needed no malice at all to read it — but it is now labelled as defence in depth rather than as the boundary.
The cost, stated plainly
vsphere is verified on the release branch rather than on the PR that changes it. That is a real gap, accepted knowingly:
vsphere/changes a handful of times a year, and most of its current runs are triggered by unrelated CI edits viaSHARED_PATHS, not by vsphere changes.Alternatives considered and rejected for now:
SHARED_PATHSmade it fire on ~1 commit in 6.The durable fix
This job should not exist. VMware now publishes the SDK to public PyPI under renamed packages —
vmware-vapi-runtime,vmware-vapi-common-client,pyvmomi, all at 9.1.0.0 — and serves the NSX/VMC wheels from its own public PEP 503 index. The names we are blocked on (vsphere-automation-sdk,vapi-runtime) are squatted0.0.1placeholders. We are on the private index only because of the ancientvsphere-automation-sdk==1.82.0pin. Modernising it deletes the credential, this job, and the PR coverage gap in one change. Ticket to follow.Validation
shellcheckclean on both scripts;actionlintclean; Zizmor clean (4 ignored, 2 suppressed).pull_request→private_checks=[],deferred_private_checks=["vsphere"], notice emitted.push/workflow_dispatch→private_checks=["vsphere"],deferred=[].fetch_private_wheels.shwithGITHUB_EVENT_NAME=pull_requestexits 1 before touching any credential.Jira: STAC-25540