diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8004983 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..42a2a1b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Native build + runs-on: macos-26 + timeout-minutes: 15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - name: Validate build script syntax + run: zsh -n build.sh + - name: Build and verify the native bundle + run: ./build.sh + - name: Validate bundle metadata and signature + run: | + plutil -lint build/MenuBarNetToggle.app/Contents/Info.plist + codesign --verify --deep --strict --verbose=2 build/MenuBarNetToggle.app + lipo build/MenuBarNetToggle.app/Contents/MacOS/MenuBarNetToggle -verify_arch arm64 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..9ed0af6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,103 @@ +name: CodeQL + +on: + push: + branches: [main] + pull_request: + schedule: + - cron: '45 7 * * 1' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + strategy: + fail-fast: false + matrix: + include: + - language: swift + runner: macos-26 + build-mode: manual + - language: actions + runner: ubuntu-latest + build-mode: none + runs-on: ${{ matrix.runner }} + timeout-minutes: 45 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - name: Initialize CodeQL + uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + - name: Compile the native Swift application + if: matrix.language == 'swift' + run: ./build.sh + - name: Analyze without a security write token + uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 + with: + category: /language:${{ matrix.language }} + output: ${{ runner.temp }}/codeql-results + upload: never + upload-database: false + - name: Retain analysis for the isolated upload job + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 + with: + name: codeql-${{ matrix.language }} + path: ${{ runner.temp }}/codeql-results/*.sarif + if-no-files-found: error + retention-days: 1 + + publish: + name: Publish analysis (${{ matrix.language }}) + needs: analyze + strategy: + fail-fast: false + matrix: + language: [swift, actions] + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + actions: read + contents: read + security-events: write + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 + with: + name: codeql-${{ matrix.language }} + path: ${{ runner.temp }}/codeql-results + - name: Upload the completed analysis + uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4 + with: + sarif_file: ${{ runner.temp }}/codeql-results + category: /language:${{ matrix.language }} + wait-for-processing: true + + complete: + name: CodeQL source analysis + if: always() + needs: [analyze, publish] + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Require analysis and upload for every language + env: + ANALYSIS_RESULT: ${{ needs.analyze.result }} + PUBLISH_RESULT: ${{ needs.publish.result }} + run: | + if [[ "$ANALYSIS_RESULT" != success || "$PUBLISH_RESULT" != success ]]; then + printf 'CodeQL requires successful extraction, analysis, and upload for every configured language. Analysis=%s upload=%s\n' "$ANALYSIS_RESULT" "$PUBLISH_RESULT" >&2 + exit 1 + fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..aeeb749 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,8 @@ +# Interface Sentinel repository instructions + +- Preserve the existing `com.netctl` application and helper identities, allowlist contract, launchd domains, and migration behavior. +- Keep changes uncommitted until the user authorizes a commit; commit, push, PR creation, merge, release, deployment, and privileged installation each require authorization covering that operation. +- Keep the `Native build` PR check emitted for every PR. Run `build.sh`, plist validation, and strict codesign verification as defined in `.github/workflows/ci.yml`. +- CodeQL must trace the explicit Swift compilation in `build.sh`; verify successful Swift analysis at the reviewed revision. +- Hosted CI may compile and verify the bundle but must not launch the application, install a helper, modify launchd, or enforce interface policy. +- Changes to privileged paths, helper lifecycle, allowlists, quoting, launchd, or interface enforcement also require direct local macOS integration evidence on an explicitly authorized noncritical Mac with local recovery access.