diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..20a1986 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + open-pull-requests-limit: 5 + - package-ecosystem: npm + directory: /scripts/branding + schedule: + interval: monthly + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c0c90a..31862db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,27 @@ concurrency: cancel-in-progress: true jobs: + branding-type-check: + name: Branding TypeScript check + runs-on: ubuntu-latest + timeout-minutes: 10 + defaults: + run: + working-directory: scripts/branding + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Set up Node + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7 + with: + node-version: '24' + - name: Install locked branding dependencies + run: npm ci --ignore-scripts + - name: Check branding TypeScript + run: npm run check + build-and-test: runs-on: macos-26 timeout-minutes: 20 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..922611a --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,111 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: '17 6 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 45 + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - language: swift + os: macos-26 + build-mode: manual + - language: javascript-typescript + os: ubuntu-latest + build-mode: none + - language: actions + os: ubuntu-latest + build-mode: none + env: + DEVELOPER_DIR: ${{ matrix.language == 'swift' && '/Applications/Xcode_26.4.1.app/Contents/Developer' || '' }} + steps: + - name: Check out source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + - name: Initialize CodeQL + uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + - name: Build Swift source for extraction + if: matrix.language == 'swift' + run: xcodebuild -project SystemProfilerExplorer.xcodeproj -scheme SystemProfilerExplorer -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO build test + - name: Analyze source without upload permissions + uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 + with: + category: /language:${{ matrix.language }} + output: results + upload: never + upload-database: false + - name: Retain analysis results for the upload job + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 + with: + name: codeql-results-${{ matrix.language }} + path: results/*.sarif + if-no-files-found: error + retention-days: 7 + + upload: + name: Upload CodeQL (${{ matrix.language }}) + needs: analyze + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + security-events: write + strategy: + fail-fast: false + matrix: + language: [swift, javascript-typescript, actions] + steps: + - name: Download this run's analysis results + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 + with: + name: codeql-results-${{ matrix.language }} + path: results + - name: Upload SARIF without checking out or running repository code + uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 + with: + sarif_file: results + category: /language:${{ matrix.language }} + ref: ${{ github.ref }} + sha: ${{ github.sha }} + wait-for-processing: true + + results: + name: CodeQL results + needs: [analyze, upload] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: {} + steps: + - name: Require completed analysis and processed uploads + env: + ANALYSIS_RESULT: ${{ needs.analyze.result }} + UPLOAD_RESULT: ${{ needs.upload.result }} + run: | + if [[ "$ANALYSIS_RESULT" != success || "$UPLOAD_RESULT" != success ]]; then + printf 'CodeQL did not complete: analysis=%s upload=%s\n' "$ANALYSIS_RESULT" "$UPLOAD_RESULT" >&2 + exit 1 + fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a594b7b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,15 @@ +# System Profiler Explorer + +## Validation and evidence + +- Read `CONTRIBUTING.md` and `SECURITY.md`. Run `./scripts/check-publication-boundary.sh`, then `xcodebuild -project SystemProfilerExplorer.xcodeproj -scheme SystemProfilerExplorer -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO build test` before a PR. +- Keep the checked-in Xcode project; regenerate it with XcodeGen only when `project.yml` changes. Preserve the publication-boundary gate and native build/test CI. +- Branding dependencies live in `scripts/branding`; use its lockfile and run `npm ci --ignore-scripts` followed by `npm run check` there. Type checks do not regenerate or validate rendered artwork. +- Keep collection read-only and separate reported values from interpretation. Tests and CodeQL do not establish live collection on every supported Mac or compromise. +- Never include raw profiler reports, private snapshots, identifiers, installed-software inventories, host timestamps, or screenshots with private values in Git or PRs. Use synthetic fixtures; review the documented anonymized-sample exception before sharing. +- Verify successful Swift, JavaScript/TypeScript, and GitHub Actions CodeQL analyses at the candidate revision; scanner configuration or an older run does not establish current coverage. +- Keep CodeQL extraction/build jobs read-only. Upload SARIF in a separate job that runs no repository code, and preserve the strict `CodeQL results` gate across every language. + +## Publication + +- `scripts/build-release.sh` builds a local distribution candidate. Tags and CI do not publish a product release; distribution signing, notarization, tagging, and publication require authorization covering those actions.