Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 87 additions & 38 deletions .github/workflows/squad-standalone-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -429,19 +429,41 @@ jobs:
exit 1
fi

- name: Preflight - verify Homebrew tap token
env:
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
set -euo pipefail
login="$(gh api user --jq '.login')" || {
echo "::error::HOMEBREW_TAP_TOKEN failed to authenticate against the GitHub API. The token is likely invalid, expired, or revoked and must be rotated by a maintainer with write access to bradygaster/homebrew-squad."
exit 1
}
echo "Authenticated as: ${login}"
push_access="$(gh api repos/bradygaster/homebrew-squad --jq '.permissions.push // false')"
echo "Push access to bradygaster/homebrew-squad: ${push_access}"
if [ "${push_access}" != "true" ]; then
echo "::error::HOMEBREW_TAP_TOKEN authenticates as '${login}', but that account/token does not have push access to bradygaster/homebrew-squad."
exit 1
fi

- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8
with:
name: packaging-manifests
path: packaging

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
with:
repository: bradygaster/homebrew-squad
ref: main
path: homebrew-tap
fetch-depth: 1
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
persist-credentials: true
- name: Clone Homebrew tap (anonymous read; bradygaster/homebrew-squad is public)
run: |
set -euo pipefail
git clone --depth 1 --branch main https://github.com/bradygaster/homebrew-squad.git homebrew-tap

- name: Configure Homebrew tap push credential (scoped locally; never passed to the read-only clone)
env:
TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
working-directory: homebrew-tap
run: |
set -euo pipefail
auth_header="Authorization: basic $(printf 'x-access-token:%s' "${TOKEN}" | base64 -w0)"
git config --local http.https://github.com/.extraheader "${auth_header}"

- name: Publish cask to the tap
env:
Expand Down Expand Up @@ -571,6 +593,23 @@ jobs:
exit 1
fi

- name: Preflight - verify WinGet publish token
env:
GH_TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
run: |
set -euo pipefail
login="$(gh api user --jq '.login')" || {
echo "::error::WINGET_CREATE_GITHUB_TOKEN failed to authenticate against the GitHub API. The token is likely invalid, expired, or revoked and must be rotated by a maintainer with push access to tamirdresher/winget-pkgs."
exit 1
}
echo "Authenticated as: ${login}"
push_access="$(gh api repos/tamirdresher/winget-pkgs --jq '.permissions.push // false')"
echo "Push access to tamirdresher/winget-pkgs: ${push_access}"
if [ "${push_access}" != "true" ]; then
echo "::error::WINGET_CREATE_GITHUB_TOKEN authenticates as '${login}', but that account/token does not have push access to tamirdresher/winget-pkgs."
exit 1
fi

- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8
with:
name: packaging-manifests
Expand Down Expand Up @@ -609,15 +648,14 @@ jobs:
echo "package_identifier=${PACKAGE_IDENTIFIER}" >> "${GITHUB_OUTPUT}"
echo "package_root=${package_root}" >> "${GITHUB_OUTPUT}"

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
with:
repository: microsoft/winget-pkgs
ref: master
path: winget-base
fetch-depth: 1
sparse-checkout: ${{ steps.release.outputs.package_root }}
token: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
persist-credentials: false
- name: Clone WinGet manifests directory (read-only, public repo; no credential needed)
env:
PACKAGE_ROOT: ${{ steps.release.outputs.package_root }}
run: |
set -euo pipefail
git clone --no-checkout --depth 1 --branch master --filter=blob:none https://github.com/microsoft/winget-pkgs.git winget-base
git -C winget-base sparse-checkout set "${PACKAGE_ROOT}"
git -C winget-base checkout master

- name: Check WinGet publication state
id: guard
Expand Down Expand Up @@ -702,29 +740,40 @@ jobs:
echo "skip=false" >> "${GITHUB_OUTPUT}"
echo "branch_exists=${branch_exists}" >> "${GITHUB_OUTPUT}"

- name: Check out existing WinGet version branch
- name: Check out existing WinGet version branch (anonymous read; tamirdresher/winget-pkgs is public)
if: steps.guard.outputs.skip == 'false' && steps.guard.outputs.branch_exists == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
with:
repository: tamirdresher/winget-pkgs
ref: ${{ steps.release.outputs.branch }}
path: winget-pkgs
fetch-depth: 1
sparse-checkout: ${{ steps.release.outputs.package_root }}
token: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
persist-credentials: true

- name: Check out WinGet master for a new version branch
env:
BRANCH: ${{ steps.release.outputs.branch }}
PACKAGE_ROOT: ${{ steps.release.outputs.package_root }}
run: |
set -euo pipefail
git clone --no-checkout --depth 1 --branch "${BRANCH}" --filter=blob:none \
https://github.com/tamirdresher/winget-pkgs.git winget-pkgs
git -C winget-pkgs sparse-checkout set "${PACKAGE_ROOT}"
git -C winget-pkgs checkout "${BRANCH}"

- name: Configure existing-branch push credential (scoped locally; never passed to the read-only clone)
if: steps.guard.outputs.skip == 'false' && steps.guard.outputs.branch_exists == 'true'
env:
TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
working-directory: winget-pkgs
run: |
set -euo pipefail
auth_header="Authorization: basic $(printf 'x-access-token:%s' "${TOKEN}" | base64 -w0)"
git config --local http.https://github.com/.extraheader "${auth_header}"

- name: Clone WinGet master for a new version branch (credential scoped locally for the later push)
if: steps.guard.outputs.skip == 'false' && steps.guard.outputs.branch_exists == 'false'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
with:
repository: microsoft/winget-pkgs
ref: master
path: winget-pkgs
fetch-depth: 1
sparse-checkout: ${{ steps.release.outputs.package_root }}
token: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
persist-credentials: true
env:
TOKEN: ${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}
PACKAGE_ROOT: ${{ steps.release.outputs.package_root }}
run: |
set -euo pipefail
git clone --no-checkout --depth 1 --branch master --filter=blob:none https://github.com/microsoft/winget-pkgs.git winget-pkgs
git -C winget-pkgs sparse-checkout set "${PACKAGE_ROOT}"
git -C winget-pkgs checkout master
auth_header="Authorization: basic $(printf 'x-access-token:%s' "${TOKEN}" | base64 -w0)"
git -C winget-pkgs config --local http.https://github.com/.extraheader "${auth_header}"

- name: Push manifests and open upstream PR
if: steps.guard.outputs.skip == 'false'
Expand Down
51 changes: 39 additions & 12 deletions test/standalone-release-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,16 +613,32 @@ describe('automated package publication', () => {
expect(wingetGate.run).toMatch(/classic PAT.*public_repo/);
});

it('updates only the tap cask and skips an identical manifest', () => {
const checkout = homebrew.steps?.find(
(step) => step.with?.repository === 'bradygaster/homebrew-squad',
);
expect(checkout?.uses).toMatch(/^actions\/checkout@[0-9a-f]{40}$/);
expect(checkout?.with).toMatchObject({
ref: 'main',
path: 'homebrew-tap',
token: '${{ secrets.HOMEBREW_TAP_TOKEN }}',
});
it('clones the tap anonymously and scopes the push credential locally', () => {
const clone = stepNamed(
homebrew,
'Clone Homebrew tap (anonymous read; bradygaster/homebrew-squad is public)',
);
expect(clone.run).toContain(
'git clone --depth 1 --branch main https://github.com/bradygaster/homebrew-squad.git homebrew-tap',
);
// The read-only clone must never receive the publish token: if it did, the
// same auth-setup path that failed in production (actions/checkout
// configuring credentials for the initial fetch of an external repo)
// would be reintroduced.
expect(clone.run).not.toContain('secrets.HOMEBREW_TAP_TOKEN');
expect(clone.env ?? {}).not.toHaveProperty('HOMEBREW_TAP_TOKEN');
expect(homebrew.steps?.some((step) => step.with?.repository === 'bradygaster/homebrew-squad')).toBe(false);

const credential = stepNamed(
homebrew,
'Configure Homebrew tap push credential (scoped locally; never passed to the read-only clone)',
);
expect(credential['working-directory']).toBe('homebrew-tap');
expect(credential.env?.TOKEN).toBe('${{ secrets.HOMEBREW_TAP_TOKEN }}');
expect(credential.run).toContain('git config --local http.https://github.com/.extraheader');
expect(credential.run).not.toContain('--global');
// The token must not be echoed/logged anywhere in the credential step.
expect(credential.run).not.toMatch(/echo.*TOKEN/);

const publish = stepNamed(homebrew, 'Publish cask to the tap').run ?? '';
expect(publish).toContain('../packaging/homebrew/${CASK}.rb');
Expand Down Expand Up @@ -666,10 +682,21 @@ describe('automated package publication', () => {

const existingCheckout = stepNamed(
winget,
'Check out existing WinGet version branch',
'Check out existing WinGet version branch (anonymous read; tamirdresher/winget-pkgs is public)',
);
expect(existingCheckout.with?.repository).toBe('tamirdresher/winget-pkgs');
expect(existingCheckout.if).toContain("branch_exists == 'true'");
expect(existingCheckout.run).toContain(
'git clone --no-checkout --depth 1 --branch "${BRANCH}" --filter=blob:none \\\n https://github.com/tamirdresher/winget-pkgs.git winget-pkgs',
);
expect(existingCheckout.run).not.toContain('secrets.WINGET_CREATE_GITHUB_TOKEN');
expect(winget.steps?.some((step) => step.with?.repository === 'tamirdresher/winget-pkgs')).toBe(false);

const existingCredential = stepNamed(
winget,
'Configure existing-branch push credential (scoped locally; never passed to the read-only clone)',
);
expect(existingCredential.env?.TOKEN).toBe('${{ secrets.WINGET_CREATE_GITHUB_TOKEN }}');
expect(existingCredential.run).toContain('git config --local http.https://github.com/.extraheader');

const publish = stepNamed(winget, 'Push manifests and open upstream PR').run ?? '';
expect(publish).toContain('../packaging/winget/${manifest_name}');
Expand Down
Loading