-
Notifications
You must be signed in to change notification settings - Fork 38
[codex] Add Swift E2E coverage #2408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| self-hosted-runner: | ||
| # Labels of self-hosted runner in array of strings. | ||
| labels: | ||
| - macOS | ||
| - packrat-e2e | ||
|
|
||
| # Configuration variables in array of strings defined in your repository or | ||
| # organization. `null` means disabling configuration variables check. | ||
| # Empty array means no configuration variable is allowed. | ||
| config-variables: null | ||
|
|
||
| # Configuration for file paths. The keys are glob patterns to match to file | ||
| # paths relative to the repository root. The values are the configurations for | ||
| # the file paths. Note that the path separator is always '/'. | ||
| # The following configurations are available. | ||
| # | ||
| # "ignore" is an array of regular expression patterns. Matched error messages | ||
| # are ignored. This is similar to the "-ignore" command line option. | ||
| paths: | ||
| # .github/workflows/**/*.yml: | ||
| # ignore: [] |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,246 @@ | ||||||||||||||||||
| name: Swift E2E Tests | ||||||||||||||||||
|
|
||||||||||||||||||
| on: | ||||||||||||||||||
| pull_request: | ||||||||||||||||||
| branches: ["**"] | ||||||||||||||||||
| paths: | ||||||||||||||||||
| - "apps/swift/**" | ||||||||||||||||||
| - "packages/api/src/**" | ||||||||||||||||||
| - "packages/api/drizzle/**" | ||||||||||||||||||
| - "packages/api/package.json" | ||||||||||||||||||
| - "package.json" | ||||||||||||||||||
| - "bun.lock" | ||||||||||||||||||
| - ".github/workflows/swift-e2e.yml" | ||||||||||||||||||
| push: | ||||||||||||||||||
| branches: [main, development] | ||||||||||||||||||
| paths: | ||||||||||||||||||
| - "apps/swift/**" | ||||||||||||||||||
| - "packages/api/src/**" | ||||||||||||||||||
| - "packages/api/drizzle/**" | ||||||||||||||||||
| - "packages/api/package.json" | ||||||||||||||||||
| - "package.json" | ||||||||||||||||||
| - "bun.lock" | ||||||||||||||||||
| - ".github/workflows/swift-e2e.yml" | ||||||||||||||||||
| schedule: | ||||||||||||||||||
| - cron: "17 8 * * *" | ||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||
| inputs: | ||||||||||||||||||
| run_macos_ui: | ||||||||||||||||||
| description: "Run the full macOS UI suite on a self-hosted Mac runner" | ||||||||||||||||||
| required: false | ||||||||||||||||||
| type: boolean | ||||||||||||||||||
| default: true | ||||||||||||||||||
| run_ios_ui: | ||||||||||||||||||
| description: "Run the exploratory Swift iOS UI suite on a GitHub-hosted macOS runner" | ||||||||||||||||||
| required: false | ||||||||||||||||||
| type: boolean | ||||||||||||||||||
| default: false | ||||||||||||||||||
|
|
||||||||||||||||||
| concurrency: | ||||||||||||||||||
| group: ${{ github.workflow }}-${{ github.ref }} | ||||||||||||||||||
| cancel-in-progress: true | ||||||||||||||||||
|
|
||||||||||||||||||
| permissions: | ||||||||||||||||||
| contents: read | ||||||||||||||||||
|
|
||||||||||||||||||
| env: | ||||||||||||||||||
| XCODE_VERSION: "26.2" | ||||||||||||||||||
| E2E_API_BASE_URL: ${{ secrets.SWIFT_E2E_API_BASE_URL }} | ||||||||||||||||||
| E2E_EMAIL: ${{ secrets.E2E_TEST_EMAIL }} | ||||||||||||||||||
| E2E_PASSWORD: ${{ secrets.E2E_TEST_PASSWORD }} | ||||||||||||||||||
| E2E_SCREENSHOT_DIR: ${{ github.workspace }}/apps/swift/TestResults/screenshots | ||||||||||||||||||
| PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN: ${{ secrets.PACKRAT_NATIVEWIND_UI_GITHUB_TOKEN }} | ||||||||||||||||||
|
|
||||||||||||||||||
| jobs: | ||||||||||||||||||
| macos-ui: | ||||||||||||||||||
| name: macOS Swift UI E2E | ||||||||||||||||||
| runs-on: [self-hosted, macOS, packrat-e2e] | ||||||||||||||||||
| timeout-minutes: 45 | ||||||||||||||||||
| if: > | ||||||||||||||||||
| github.event_name == 'schedule' || | ||||||||||||||||||
| github.event_name == 'push' || | ||||||||||||||||||
| (github.event_name == 'workflow_dispatch' && inputs.run_macos_ui) || | ||||||||||||||||||
| (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) | ||||||||||||||||||
|
|
||||||||||||||||||
| steps: | ||||||||||||||||||
| - name: Checkout repository | ||||||||||||||||||
| uses: actions/checkout@v6 | ||||||||||||||||||
|
|
||||||||||||||||||
|
Comment on lines
+66
to
+68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Check the workflow file and examine the specified lines
fd 'swift-e2e.yml' --type fRepository: PackRat-AI/PackRat Length of output: 44 🏁 Script executed: # Read the workflow file to see lines 66-68 and 166-168
cat -n .github/workflows/swift-e2e.yml | sed -n '60,75p; 160,175p'Repository: PackRat-AI/PackRat Length of output: 1246 🌐 Web query:
💡 Result: Setting Citations:
Pin actions/checkout to commit SHA and disable credential persistence in both jobs.
Suggested patch - name: Checkout repository
uses: actions/checkout@<full_commit_sha>
+ with:
+ persist-credentials: falseAlso applies to: 166-168 🧰 Tools🪛 zizmor (1.25.2)[warning] 66-67: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 67-67: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||
| - name: Setup Xcode | ||||||||||||||||||
| uses: maxim-lobanov/setup-xcode@v1 | ||||||||||||||||||
| with: | ||||||||||||||||||
| xcode-version: ${{ env.XCODE_VERSION }} | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Setup Bun | ||||||||||||||||||
| uses: oven-sh/setup-bun@v2 | ||||||||||||||||||
| with: | ||||||||||||||||||
| bun-version: latest | ||||||||||||||||||
| cache: true | ||||||||||||||||||
|
Comment on lines
+75
to
+78
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Check if the workflow file exists and read the relevant lines
if [ -f ".github/workflows/swift-e2e.yml" ]; then
echo "=== Lines 75-78 ==="
sed -n '75,78p' ".github/workflows/swift-e2e.yml"
echo ""
echo "=== Lines 175-178 ==="
sed -n '175,178p' ".github/workflows/swift-e2e.yml"
else
echo "File not found: .github/workflows/swift-e2e.yml"
fiRepository: PackRat-AI/PackRat Length of output: 307 🏁 Script executed: # Search for the declared Bun version in common config files
echo "=== Searching for bun version declarations ==="
rg "bun.*version|bun@" --type json --type yaml --type toml --type md -iRepository: PackRat-AI/PackRat Length of output: 989 🏁 Script executed: # Check for all bun-version references in the workflow file
echo "=== All bun-version references in swift-e2e.yml ==="
rg "bun-version" ".github/workflows/swift-e2e.yml" -nRepository: PackRat-AI/PackRat Length of output: 181 Pin Bun version in CI instead of Both instances at lines 77 and 177 need to be updated. Suggested patch- bun-version: latest
+ bun-version: 1.3.10📝 Committable suggestion
Suggested change
🧰 Tools🪛 zizmor (1.25.2)[error] 75-75: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| - name: Install dependencies | ||||||||||||||||||
| run: bun install --frozen-lockfile | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Verify Swift E2E secrets | ||||||||||||||||||
| run: | | ||||||||||||||||||
| missing=() | ||||||||||||||||||
| [ -z "${E2E_EMAIL:-}" ] && missing+=("E2E_TEST_EMAIL") | ||||||||||||||||||
| [ -z "${E2E_PASSWORD:-}" ] && missing+=("E2E_TEST_PASSWORD") | ||||||||||||||||||
| [ -z "${E2E_API_BASE_URL:-}" ] && missing+=("SWIFT_E2E_API_BASE_URL") | ||||||||||||||||||
| [ -z "${NEON_DATABASE_URL:-}" ] && missing+=("NEON_DEV_DATABASE_URL") | ||||||||||||||||||
| if [ ${#missing[@]} -gt 0 ]; then | ||||||||||||||||||
| echo "::error::Required Swift E2E secrets missing: ${missing[*]}" | ||||||||||||||||||
| exit 1 | ||||||||||||||||||
| fi | ||||||||||||||||||
| env: | ||||||||||||||||||
| NEON_DATABASE_URL: ${{ secrets.NEON_DEV_DATABASE_URL }} | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Check Automation Mode status | ||||||||||||||||||
| run: | | ||||||||||||||||||
| automationmodetool status || true | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Generate Swift Xcode project | ||||||||||||||||||
| run: bun run swift | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Seed E2E test user | ||||||||||||||||||
| run: bun run --filter @packrat/api db:seed:e2e-user | ||||||||||||||||||
| env: | ||||||||||||||||||
| NEON_DATABASE_URL: ${{ secrets.NEON_DEV_DATABASE_URL }} | ||||||||||||||||||
| E2E_TEST_EMAIL: ${{ env.E2E_EMAIL }} | ||||||||||||||||||
| E2E_TEST_PASSWORD: ${{ env.E2E_PASSWORD }} | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Run macOS Swift UI E2E | ||||||||||||||||||
| run: | | ||||||||||||||||||
| if [ "${{ github.event_name }}" = "pull_request" ]; then | ||||||||||||||||||
| caffeinate -dimsu bun run e2e:swift:mac-smoke | ||||||||||||||||||
| else | ||||||||||||||||||
| caffeinate -dimsu bun run e2e:swift:mac-ui | ||||||||||||||||||
| fi | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Summarize macOS xcresult | ||||||||||||||||||
| if: always() | ||||||||||||||||||
| run: | | ||||||||||||||||||
| result="$(find apps/swift/TestResults -maxdepth 1 -name '*.xcresult' -type d | sort | tail -1)" | ||||||||||||||||||
| if [ -z "$result" ]; then | ||||||||||||||||||
| echo "No xcresult bundle found." | ||||||||||||||||||
| exit 0 | ||||||||||||||||||
| fi | ||||||||||||||||||
| echo "### macOS Swift UI E2E" >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||
| echo "\`$result\`" >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||
| xcrun xcresulttool get test-results summary --path "$result" | tee -a "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Upload macOS xcresult | ||||||||||||||||||
| if: always() | ||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||
| with: | ||||||||||||||||||
| name: swift-macos-ui-xcresult | ||||||||||||||||||
| path: apps/swift/TestResults/*.xcresult | ||||||||||||||||||
| retention-days: 14 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Upload macOS screenshots | ||||||||||||||||||
| if: always() | ||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||
| with: | ||||||||||||||||||
| name: swift-macos-ui-screenshots | ||||||||||||||||||
| path: apps/swift/TestResults/screenshots/ | ||||||||||||||||||
| if-no-files-found: ignore | ||||||||||||||||||
| retention-days: 14 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Upload macOS failure triage bundle | ||||||||||||||||||
| if: failure() | ||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||
| with: | ||||||||||||||||||
| name: swift-macos-ui-failure-triage | ||||||||||||||||||
| path: apps/swift/TestResults/ | ||||||||||||||||||
| if-no-files-found: ignore | ||||||||||||||||||
| retention-days: 14 | ||||||||||||||||||
|
|
||||||||||||||||||
| ios-ui: | ||||||||||||||||||
| name: iOS Swift UI E2E (Exploratory) | ||||||||||||||||||
| runs-on: macos-15 | ||||||||||||||||||
| timeout-minutes: 60 | ||||||||||||||||||
| if: > | ||||||||||||||||||
| github.event_name == 'schedule' || | ||||||||||||||||||
| (github.event_name == 'workflow_dispatch' && inputs.run_ios_ui) | ||||||||||||||||||
|
|
||||||||||||||||||
| steps: | ||||||||||||||||||
| - name: Checkout repository | ||||||||||||||||||
| uses: actions/checkout@v6 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Setup Xcode | ||||||||||||||||||
| uses: maxim-lobanov/setup-xcode@v1 | ||||||||||||||||||
| with: | ||||||||||||||||||
| xcode-version: ${{ env.XCODE_VERSION }} | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Setup Bun | ||||||||||||||||||
| uses: oven-sh/setup-bun@v2 | ||||||||||||||||||
| with: | ||||||||||||||||||
| bun-version: latest | ||||||||||||||||||
| cache: true | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Install dependencies | ||||||||||||||||||
| run: bun install --frozen-lockfile | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Verify Swift E2E secrets | ||||||||||||||||||
| run: | | ||||||||||||||||||
| missing=() | ||||||||||||||||||
| [ -z "${E2E_EMAIL:-}" ] && missing+=("E2E_TEST_EMAIL") | ||||||||||||||||||
| [ -z "${E2E_PASSWORD:-}" ] && missing+=("E2E_TEST_PASSWORD") | ||||||||||||||||||
| [ -z "${E2E_API_BASE_URL:-}" ] && missing+=("SWIFT_E2E_API_BASE_URL") | ||||||||||||||||||
| [ -z "${NEON_DATABASE_URL:-}" ] && missing+=("NEON_DEV_DATABASE_URL") | ||||||||||||||||||
| if [ ${#missing[@]} -gt 0 ]; then | ||||||||||||||||||
| echo "::error::Required Swift E2E secrets missing: ${missing[*]}" | ||||||||||||||||||
| exit 1 | ||||||||||||||||||
| fi | ||||||||||||||||||
| env: | ||||||||||||||||||
| NEON_DATABASE_URL: ${{ secrets.NEON_DEV_DATABASE_URL }} | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Generate Swift Xcode project | ||||||||||||||||||
| run: bun run swift | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Seed E2E test user | ||||||||||||||||||
| run: bun run --filter @packrat/api db:seed:e2e-user | ||||||||||||||||||
| env: | ||||||||||||||||||
| NEON_DATABASE_URL: ${{ secrets.NEON_DEV_DATABASE_URL }} | ||||||||||||||||||
| E2E_TEST_EMAIL: ${{ env.E2E_EMAIL }} | ||||||||||||||||||
| E2E_TEST_PASSWORD: ${{ env.E2E_PASSWORD }} | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Run iOS Swift UI E2E | ||||||||||||||||||
| run: bun run e2e:swift:ios | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Summarize iOS xcresult | ||||||||||||||||||
| if: always() | ||||||||||||||||||
| run: | | ||||||||||||||||||
| result="$(find apps/swift/TestResults -maxdepth 1 -name '*.xcresult' -type d | sort | tail -1)" | ||||||||||||||||||
| if [ -z "$result" ]; then | ||||||||||||||||||
| echo "No xcresult bundle found." | ||||||||||||||||||
| exit 0 | ||||||||||||||||||
| fi | ||||||||||||||||||
| echo "### iOS Swift UI E2E" >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||
| echo "\`$result\`" >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||
| xcrun xcresulttool get test-results summary --path "$result" | tee -a "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Upload iOS xcresult | ||||||||||||||||||
| if: always() | ||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||
| with: | ||||||||||||||||||
| name: swift-ios-ui-xcresult | ||||||||||||||||||
| path: apps/swift/TestResults/*.xcresult | ||||||||||||||||||
| retention-days: 14 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Upload iOS screenshots | ||||||||||||||||||
| if: always() | ||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||
| with: | ||||||||||||||||||
| name: swift-ios-ui-screenshots | ||||||||||||||||||
| path: apps/swift/TestResults/screenshots/ | ||||||||||||||||||
| if-no-files-found: ignore | ||||||||||||||||||
| retention-days: 14 | ||||||||||||||||||
|
|
||||||||||||||||||
| - name: Upload iOS failure triage bundle | ||||||||||||||||||
| if: failure() | ||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||
| with: | ||||||||||||||||||
| name: swift-ios-ui-failure-triage | ||||||||||||||||||
| path: apps/swift/TestResults/ | ||||||||||||||||||
| if-no-files-found: ignore | ||||||||||||||||||
| retention-days: 14 | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| # PackRat Swift Testing | ||
|
|
||
| The generated Xcode project is not committed. Regenerate it after changing | ||
| `project.yml`: | ||
|
|
||
| ```sh | ||
| bun swift | ||
| ``` | ||
|
|
||
| If Xcode or SwiftPM reports a temporary-directory error on this machine, ensure | ||
| the configured temp directory exists: | ||
|
|
||
| ```sh | ||
| mkdir -p /Volumes/CrucialX10/tmp/andrewbierman | ||
| ``` | ||
|
|
||
| ## Commands | ||
|
|
||
| ```sh | ||
| bun run test:swift:runner | ||
| bun run test:swift:unit | ||
| bun run e2e:swift:ios-smoke | ||
| bun run e2e:swift:ios | ||
| bun run e2e:swift:mac | ||
| bun run e2e:swift:mac-smoke | ||
| bun run e2e:swift:mac-ui | ||
| ``` | ||
|
|
||
| `e2e:swift` defaults to iOS UI tests for compatibility with the original | ||
| runner. All Xcode result bundles are written under `apps/swift/TestResults/`. | ||
|
|
||
| Smoke modes are intentionally small PR gates: | ||
|
|
||
| - `e2e:swift:mac-smoke`: macOS login, sidebar navigation, and pack create/add-item. | ||
| - `e2e:swift:ios-smoke`: iOS login, tab navigation, and pack create. | ||
|
|
||
| Full modes are the platform confidence gates: | ||
|
|
||
| - `e2e:swift:mac-ui`: full native macOS app UI suite. | ||
| - `e2e:swift:ios`: exploratory native Swift iOS app UI suite. This is separate | ||
| from the existing Expo iOS app, which remains covered by Maestro. | ||
|
|
||
| UI modes require credentials in the process environment or `.env.local`: | ||
|
|
||
| ```sh | ||
| E2E_EMAIL=... | ||
| E2E_PASSWORD=... | ||
| ``` | ||
|
|
||
| The runner also accepts `E2E_TEST_EMAIL` and `E2E_TEST_PASSWORD`, then forwards | ||
| them to XCTest as `E2E_EMAIL` and `E2E_PASSWORD`. Credential values are not | ||
| printed by the runner. | ||
|
|
||
| Set `E2E_API_BASE_URL` to point UI tests at a specific API worker without | ||
| changing the app's saved preferences: | ||
|
|
||
| ```sh | ||
| E2E_API_BASE_URL=http://localhost:8788 | ||
| ``` | ||
|
|
||
| ## CI | ||
|
|
||
| Swift E2E CI is defined in `.github/workflows/swift-e2e.yml`. | ||
|
|
||
| - Pull requests run the macOS smoke subset on a self-hosted Mac runner. | ||
| - Pushes, scheduled runs, and manual macOS runs execute the full macOS suite. | ||
| - Swift iOS runs nightly or manually and is labeled exploratory while the Expo | ||
| app remains the production iOS app. | ||
| - Each CI run uploads `.xcresult` bundles, screenshots, failure triage artifacts, | ||
| and a GitHub step summary generated with `xcresulttool`. | ||
|
|
||
| See `docs/ci/swift-e2e-runner.md` for self-hosted Mac runner setup. | ||
|
|
||
| ## Data Isolation | ||
|
|
||
| Swift E2E tests use unique names for records they create. That keeps repeated | ||
| runs safe against shared account state, but it does not fully clean historical | ||
| test data from the backend. If the shared E2E account starts accumulating enough | ||
| data to affect performance or assertions, add API-backed cleanup helpers or a | ||
| test-only reset endpoint and call it from the runner before/after UI modes. | ||
|
|
||
| ## Signing | ||
|
|
||
| `e2e:swift:mac` passes `CODE_SIGNING_ALLOWED=NO` so the local compile gate can | ||
| run without provisioning. | ||
|
|
||
| `e2e:swift:mac-ui` must still be signed because XCTest launches a runner app, | ||
| but the runner uses Xcode's local ad-hoc identity (`Sign to Run Locally`) so | ||
| smoke tests do not block on private-key prompts. | ||
|
|
||
| Normal signed builds use automatic signing with team `666HGMV2LU`. If command- | ||
| line signing fails with `errSecInternalComponent`, the certificate is installed | ||
| but `codesign` cannot access the private key from the login keychain. Unlock the | ||
| keychain and allow Apple tooling to use the key before rerunning: | ||
|
|
||
| ```sh | ||
| security unlock-keychain ~/Library/Keychains/login.keychain-db | ||
| security set-key-partition-list -S apple-tool:,apple: -s ~/Library/Keychains/login.keychain-db | ||
| ``` | ||
|
|
||
| ## Worktree Hygiene | ||
|
|
||
| The Swift branch is active and may move while multiple agents are working. | ||
| Fetch before editing shared Swift files, then compare against | ||
| `origin/claude/swift-mac-app-effort-tTGd7` before final verification. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: PackRat-AI/PackRat
Length of output: 9597
Pin all third-party actions to immutable commit SHAs.
Actions currently use mutable tags (
@v*), which allows silent updates that can introduce supply-chain attacks. Replace with full commit SHAs across:actions/checkout@v6(lines 67, 167)maxim-lobanov/setup-xcode@v1(lines 70, 170)oven-sh/setup-bun@v2(lines 75, 175)actions/upload-artifact@v7(lines 133, 141, 150, 224, 232, 241)🧰 Tools
🪛 zizmor (1.25.2)
[warning] 66-67: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 67-67: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Sources: Coding guidelines, Linters/SAST tools