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
2 changes: 1 addition & 1 deletion .github/github.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
},
"validate": {
"default": "scripts/commit-gate.sh",
"releaseApprovalPolicy": "uv run scripts/check-release-approvals.py (structural dry-run: one Ship approval; standalone review retained; operator config and RELEASE_CHANNELS_CONFIGURED=true required)",
"releaseApprovalPolicy": "uv run scripts/check-release-approvals.py (structural dry-run: one secretless Ship approval; standalone gates; one release secret store; live review-metadata check; owner role move and RELEASE_APPROVALS_CONFIGURED=true required)",
"ciChangeScope": "python3 scripts/ci-change-scope.py --base <base-sha> (pull requests only; skips swift build, swift test, and the companion builds when every changed path is documentation or validation tooling; unknown paths run everything; pushes to main and CodeQL always run in full)",
"companionUploadFixtureTools": "CONTEXT_PANEL_UPLOAD_FIXTURE_TOOLS_DIR=<dir> scripts/upload-app-store-connect-companion-app.sh --export-only <other arguments> (test-only seam for fixture xcodebuild and codesign; refused for uploads)",
"cloudKitCompanionSchema": "scripts/validate-cloudkit-companion-schema.sh",
Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/app-store-connect-companion-upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -91,13 +92,41 @@ jobs:
--version "${INPUT_VERSION}" \
--build-number "${INPUT_BUILD_NUMBER}"

- name: Require Completed Approval Setup
env:
RELEASE_APPROVALS_CONFIGURED: ${{ vars.RELEASE_APPROVALS_CONFIGURED }}
run: scripts/release-approval-config.sh

- name: Verify Required Review Environment
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py

approve:
name: Approve Release Intent
needs: guard
# Ship already reviewed this exact caller intent; all other callers need review.
if: ${{ !(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository)) }}
runs-on: ubuntu-latest
environment: release-approval
permissions:
contents: read
steps:
- name: Record Approved Intent
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
printf 'Approved release intent for version %s at %s\n' "$INPUT_VERSION" "$GITHUB_SHA"

upload:
name: Upload Companion App
needs: guard
needs: [guard, approve]
runs-on: macos-26
# Reusable workflows receive the caller identity; direct dispatch keeps review.
environment: >-
${{ github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && vars.RELEASE_CHANNELS_CONFIGURED == 'true' && 'release-channels' || 'release' }}
if: >-
${{ !cancelled() && needs.guard.result == 'success' &&
(needs.approve.result == 'success' ||
(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && needs.approve.result == 'skipped')) }}
environment: release
outputs:
build_number: ${{ steps.build.outputs.build_number }}
app_store_platform: ${{ steps.platform.outputs.app_store_platform }}
Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/app-store-connect-upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -74,13 +75,41 @@ jobs:
--version "${INPUT_VERSION}" \
--build-number "${INPUT_BUILD_NUMBER}"

- name: Require Completed Approval Setup
env:
RELEASE_APPROVALS_CONFIGURED: ${{ vars.RELEASE_APPROVALS_CONFIGURED }}
run: scripts/release-approval-config.sh

- name: Verify Required Review Environment
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py

approve:
name: Approve Release Intent
needs: guard
# Ship already reviewed this exact caller intent; all other callers need review.
if: ${{ !(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository)) }}
runs-on: ubuntu-latest
environment: release-approval
permissions:
contents: read
steps:
- name: Record Approved Intent
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
printf 'Approved release intent for version %s at %s\n' "$INPUT_VERSION" "$GITHUB_SHA"

upload:
name: Upload Mac App
needs: guard
needs: [guard, approve]
runs-on: macos-26
# Reusable workflows receive the caller identity; direct dispatch keeps review.
environment: >-
${{ github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && vars.RELEASE_CHANNELS_CONFIGURED == 'true' && 'release-channels' || 'release' }}
if: >-
${{ !cancelled() && needs.guard.result == 'success' &&
(needs.approve.result == 'success' ||
(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && needs.approve.result == 'skipped')) }}
environment: release
outputs:
build_number: ${{ steps.build.outputs.build_number }}

Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ name: CI

permissions:
contents: read
actions: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
Expand Down Expand Up @@ -53,6 +54,12 @@ jobs:
- name: Set up uv for release approval policy lint
uses: astral-sh/setup-uv@v7

- name: Verify environment metadata read capability
if: ${{ github.repository == 'cbusillo/context-panel' }}
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py --probe

- name: Check release approval graph
run: uv run scripts/check-release-approvals.py

Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -82,13 +83,41 @@ jobs:
--version "${INPUT_VERSION}" \
--build-number "${INPUT_BUILD_NUMBER}"

- name: Require Completed Approval Setup
env:
RELEASE_APPROVALS_CONFIGURED: ${{ vars.RELEASE_APPROVALS_CONFIGURED }}
run: scripts/release-approval-config.sh

- name: Verify Required Review Environment
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py

approve:
name: Approve Release Intent
needs: guard
# Ship already reviewed this exact caller intent; all other callers need review.
if: ${{ !(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository)) }}
runs-on: ubuntu-latest
environment: release-approval
permissions:
contents: read
steps:
- name: Record Approved Intent
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
printf 'Approved release intent for version %s at %s\n' "$INPUT_VERSION" "$GITHUB_SHA"

macos:
name: Build macOS App
needs: guard
needs: [guard, approve]
runs-on: macos-26
# Reusable workflows receive the caller identity; direct dispatch keeps review.
environment: >-
${{ github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && vars.RELEASE_CHANNELS_CONFIGURED == 'true' && 'release-channels' || 'release' }}
if: >-
${{ !cancelled() && needs.guard.result == 'success' &&
(needs.approve.result == 'success' ||
(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && needs.approve.result == 'skipped')) }}
environment: release
permissions:
contents: write

Expand Down
41 changes: 36 additions & 5 deletions .github/workflows/ship.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -105,9 +106,33 @@ jobs:
--version "${INPUT_VERSION}" \
--build-number "${INPUT_BUILD_NUMBER}"

- name: Require Completed Approval Setup
env:
RELEASE_APPROVALS_CONFIGURED: ${{ vars.RELEASE_APPROVALS_CONFIGURED }}
run: scripts/release-approval-config.sh

- name: Verify Required Review Environment
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py

approve:
name: Approve Release Intent
needs: guard
runs-on: ubuntu-latest
environment: release-approval
permissions:
contents: read
steps:
- name: Record Approved Intent
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
printf 'Approved release intent for version %s at %s\n' "$INPUT_VERSION" "$GITHUB_SHA"

validate:
name: Validate Release Intent
needs: guard
needs: approve
runs-on: ubuntu-latest
environment: release
outputs:
Expand Down Expand Up @@ -146,38 +171,42 @@ jobs:
uses: ./.github/workflows/release.yml
permissions:
contents: write
actions: read
with:
version: ${{ inputs.version }}
build_number: ${{ needs.validate.outputs.build_number }}
create_github_release: true
notarize: ${{ inputs.notarize_github_release }}
cloudkit_schema_receipt_base64: ${{ inputs.cloudkit_schema_receipt_base64 }}
secrets: inherit

app-store-upload:
name: Mac App Store Connect Build Upload Channel
needs: validate
if: ${{ inputs.app_store_channel != 'skip' }}
uses: ./.github/workflows/app-store-connect-upload.yml
permissions:
contents: read
actions: read
with:
version: ${{ inputs.version }}
build_number: ${{ needs.validate.outputs.build_number }}
upload: ${{ inputs.app_store_channel == 'upload' }}
cloudkit_schema_receipt_base64: ${{ inputs.cloudkit_schema_receipt_base64 }}
secrets: inherit

companion-app-store-upload:
name: Companion App Store Connect Build Upload Channel
needs: validate
if: ${{ inputs.companion_app_store_channel != 'skip' }}
uses: ./.github/workflows/app-store-connect-companion-upload.yml
permissions:
contents: read
actions: read
with:
version: ${{ inputs.version }}
build_number: ${{ needs.validate.outputs.build_number }}
platform: ${{ inputs.companion_platform }}
upload: ${{ inputs.companion_app_store_channel == 'upload' }}
cloudkit_schema_receipt_base64: ${{ inputs.cloudkit_schema_receipt_base64 }}
secrets: inherit

testflight-beta:
name: TestFlight Beta Distribution Channel
Expand All @@ -198,6 +227,9 @@ jobs:
)
}}
uses: ./.github/workflows/testflight-beta-distribution.yml
permissions:
contents: read
actions: read
with:
version: ${{ inputs.version }}
build_number: >-
Expand All @@ -208,7 +240,6 @@ jobs:
include_internal_beta_groups: ${{ inputs.include_internal_testflight_groups }}
dry_run: false
cloudkit_schema_receipt_base64: ${{ inputs.cloudkit_schema_receipt_base64 }}
secrets: inherit

summary:
name: Release Summary
Expand Down
27 changes: 26 additions & 1 deletion .github/workflows/submit-app-store-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -285,9 +286,33 @@ jobs:
--version "${INPUT_VERSION}" \
--build-number "${INPUT_BUILD_NUMBER}"

- name: Require Completed Approval Setup
env:
RELEASE_APPROVALS_CONFIGURED: ${{ vars.RELEASE_APPROVALS_CONFIGURED }}
run: scripts/release-approval-config.sh

- name: Verify Required Review Environment
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py

approve:
name: Approve Release Intent
needs: guard
runs-on: ubuntu-latest
environment: release-approval
permissions:
contents: read
steps:
- name: Record Approved Intent
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
printf 'Approved release intent for version %s at %s\n' "$INPUT_VERSION" "$GITHUB_SHA"

submit:
name: Submit App Store Review
needs: guard
needs: [guard, approve]
runs-on: macos-26
environment: release

Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/testflight-beta-distribution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v7
Expand All @@ -101,13 +102,41 @@ jobs:
--version "${INPUT_VERSION}" \
--build-number "${INPUT_BUILD_NUMBER}"

- name: Require Completed Approval Setup
env:
RELEASE_APPROVALS_CONFIGURED: ${{ vars.RELEASE_APPROVALS_CONFIGURED }}
run: scripts/release-approval-config.sh

- name: Verify Required Review Environment
env:
GH_TOKEN: ${{ github.token }}
run: python3 scripts/check-release-approval-environment.py

approve:
name: Approve Release Intent
needs: guard
# Ship already reviewed this exact caller intent; all other callers need review.
if: ${{ !(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository)) }}
runs-on: ubuntu-latest
environment: release-approval
permissions:
contents: read
steps:
- name: Record Approved Intent
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
printf 'Approved release intent for version %s at %s\n' "$INPUT_VERSION" "$GITHUB_SHA"

distribute:
name: Distribute TestFlight Beta
needs: guard
needs: [guard, approve]
runs-on: ubuntu-latest
# Reusable workflows receive the caller identity; direct dispatch keeps review.
environment: >-
${{ github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && vars.RELEASE_CHANNELS_CONFIGURED == 'true' && 'release-channels' || 'release' }}
if: >-
${{ !cancelled() && needs.guard.result == 'success' &&
(needs.approve.result == 'success' ||
(github.workflow_ref == format('{0}/.github/workflows/ship.yml@refs/heads/main', github.repository) && needs.approve.result == 'skipped')) }}
environment: release

steps:
- name: Checkout
Expand Down
Loading