From 922ac1ef815e100147be62e0dd16673d51fb3af3 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 16:53:07 +1100 Subject: [PATCH 1/5] chore: add detect-secrets pre-commit hook Prevents credential leaks before commit: - Yelp detect-secrets with baseline file - Excludes lock files and test fixtures - 28 secret pattern detectors enabled --- .github/CODEOWNERS | 65 ++++++++ .pre-commit-config.yaml | 17 ++ .secrets.baseline | 333 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .secrets.baseline diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..ecb1f02 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,65 @@ +# CODEOWNERS for cachekit-py +# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# +# These owners will be requested for review when someone opens a pull request +# that modifies code that they own. Order matters - last matching pattern wins. + +# Default: repository maintainers own everything +* @cachekit-io/maintainers + +# ───────────────────────────────────────────────────────────────────────────── +# CRITICAL SECURITY PATHS +# These require security team review for any changes +# ───────────────────────────────────────────────────────────────────────────── + +# Rust core - memory safety, FFI boundaries, cryptography +/rust/ @cachekit-io/maintainers @cachekit-io/security + +# Security-critical Python modules +/src/cachekit/serializers/ @cachekit-io/maintainers @cachekit-io/security +/src/cachekit/reliability/ @cachekit-io/maintainers @cachekit-io/security + +# ───────────────────────────────────────────────────────────────────────────── +# CI/CD AND RELEASE INFRASTRUCTURE +# Changes here can compromise supply chain +# ───────────────────────────────────────────────────────────────────────────── + +/.github/workflows/ @cachekit-io/maintainers @cachekit-io/security +/.github/CODEOWNERS @cachekit-io/maintainers +/release-please-config.json @cachekit-io/maintainers +/.release-please-manifest.json @cachekit-io/maintainers + +# ───────────────────────────────────────────────────────────────────────────── +# BUILD AND DEPENDENCY CONFIGURATION +# Supply chain attack surface +# ───────────────────────────────────────────────────────────────────────────── + +/pyproject.toml @cachekit-io/maintainers +/rust/Cargo.toml @cachekit-io/maintainers @cachekit-io/security +/rust/Cargo.lock @cachekit-io/maintainers +/.pre-commit-config.yaml @cachekit-io/maintainers + +# ───────────────────────────────────────────────────────────────────────────── +# SECURITY DOCUMENTATION +# ───────────────────────────────────────────────────────────────────────────── + +/SECURITY.md @cachekit-io/maintainers @cachekit-io/security +/.github/SECURITY.md @cachekit-io/maintainers @cachekit-io/security + +# ───────────────────────────────────────────────────────────────────────────── +# DOCUMENTATION +# Lower barrier - docs team can approve +# ───────────────────────────────────────────────────────────────────────────── + +/docs/ @cachekit-io/maintainers +/README.md @cachekit-io/maintainers +/CHANGELOG.md @cachekit-io/maintainers + +# ───────────────────────────────────────────────────────────────────────────── +# TESTS +# Test changes generally safe, but fuzzing/security tests need security review +# ───────────────────────────────────────────────────────────────────────────── + +/tests/ @cachekit-io/maintainers +/tests/security/ @cachekit-io/maintainers @cachekit-io/security +/tests/fuzz/ @cachekit-io/maintainers @cachekit-io/security diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93da3a9..7a94e00 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,3 +48,20 @@ repos: - id: check-added-large-files args: [--maxkb=1000] - id: check-merge-conflict + + # Secret scanning - prevent credential leaks + # Uses Yelp's detect-secrets with high entropy detection + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + args: + - --baseline + - .secrets.baseline + exclude: | + (?x)^( + .*\.lock$| + .*\.sum$| + tests/fixtures/.*| + docs/.*\.md$ + )$ diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..f113e1d --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,333 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + }, + { + "path": "detect_secrets.filters.regex.should_exclude_file", + "pattern": [ + ".*\\.lock$", + ".*\\.sum$" + ] + } + ], + "results": { + "docs/api-reference.md": [ + { + "type": "Secret Keyword", + "filename": "docs/api-reference.md", + "hashed_secret": "4084cee9e75572b8e2e055e114ea7458e3978b5b", + "is_verified": false, + "line_number": 674 + } + ], + "docs/configuration.md": [ + { + "type": "Hex High Entropy String", + "filename": "docs/configuration.md", + "hashed_secret": "d88aec4de8c76ada9c0172733e4300bb82abcfc7", + "is_verified": false, + "line_number": 326 + } + ], + "docs/features/zero-knowledge-encryption.md": [ + { + "type": "Secret Keyword", + "filename": "docs/features/zero-knowledge-encryption.md", + "hashed_secret": "d8eab3976a5dca3e6c91149eff8311b31399ecc7", + "is_verified": false, + "line_number": 193 + }, + { + "type": "Secret Keyword", + "filename": "docs/features/zero-knowledge-encryption.md", + "hashed_secret": "b1aa66c32f3e9119bb6d52d55f9e94b1cb8d6cbe", + "is_verified": false, + "line_number": 194 + }, + { + "type": "Secret Keyword", + "filename": "docs/features/zero-knowledge-encryption.md", + "hashed_secret": "4084cee9e75572b8e2e055e114ea7458e3978b5b", + "is_verified": false, + "line_number": 418 + } + ], + "docs/guides/serializer-guide.md": [ + { + "type": "Secret Keyword", + "filename": "docs/guides/serializer-guide.md", + "hashed_secret": "4084cee9e75572b8e2e055e114ea7458e3978b5b", + "is_verified": false, + "line_number": 801 + }, + { + "type": "Secret Keyword", + "filename": "docs/guides/serializer-guide.md", + "hashed_secret": "9d1a8d8480340f9fbc3e556ab08a6a54b68ca09d", + "is_verified": false, + "line_number": 802 + } + ], + "src/cachekit/cache_handler.py": [ + { + "type": "Secret Keyword", + "filename": "src/cachekit/cache_handler.py", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 369 + } + ], + "tests/critical/test_aad_v03_security.py": [ + { + "type": "Secret Keyword", + "filename": "tests/critical/test_aad_v03_security.py", + "hashed_secret": "05ac641e6fcf6541cfe0061aeb4b74a2d19102a2", + "is_verified": false, + "line_number": 192 + } + ], + "tests/critical/test_encrypted_at_rest.py": [ + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encrypted_at_rest.py", + "hashed_secret": "3ddb9b9043fa6e2b2a046e93c1c98e3a99169f40", + "is_verified": false, + "line_number": 116 + }, + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encrypted_at_rest.py", + "hashed_secret": "32c8d8f941cc85ee2491400fd2f214435aace6a2", + "is_verified": false, + "line_number": 248 + }, + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encrypted_at_rest.py", + "hashed_secret": "8c6ed94a5ca32d059bc8545f0981c6208b5499e0", + "is_verified": false, + "line_number": 277 + }, + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encrypted_at_rest.py", + "hashed_secret": "f3bbbd66a63d4bf1747940578ec3d0103530e21d", + "is_verified": false, + "line_number": 317 + } + ], + "tests/critical/test_encryption_integration.py": [ + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encryption_integration.py", + "hashed_secret": "a002a64509e4963dc65ac47144b6c3fac8c683ae", + "is_verified": false, + "line_number": 40 + } + ], + "tests/critical/test_encryption_wrapper.py": [ + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encryption_wrapper.py", + "hashed_secret": "650cf4deafafd0b5fc603a84a360b76a839ca5bb", + "is_verified": false, + "line_number": 113 + }, + { + "type": "Secret Keyword", + "filename": "tests/critical/test_encryption_wrapper.py", + "hashed_secret": "92dae65d522af4fc33fbfb7edb36c2e8b4a54414", + "is_verified": false, + "line_number": 126 + } + ], + "tests/integration/test_encryption_composability.py": [ + { + "type": "Secret Keyword", + "filename": "tests/integration/test_encryption_composability.py", + "hashed_secret": "332aaf8204c13d4fdb9303ebae79d51b44b609d4", + "is_verified": false, + "line_number": 89 + }, + { + "type": "Secret Keyword", + "filename": "tests/integration/test_encryption_composability.py", + "hashed_secret": "c4e2f9311369460f7302b54d50356a86adc87f97", + "is_verified": false, + "line_number": 106 + } + ], + "tests/performance/test_encryption_overhead.py": [ + { + "type": "Secret Keyword", + "filename": "tests/performance/test_encryption_overhead.py", + "hashed_secret": "d8eab3976a5dca3e6c91149eff8311b31399ecc7", + "is_verified": false, + "line_number": 103 + } + ], + "tests/unit/test_config_advanced.py.obsolete": [ + { + "type": "Basic Auth Credentials", + "filename": "tests/unit/test_config_advanced.py.obsolete", + "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", + "is_verified": false, + "line_number": 31 + } + ], + "tests/unit/test_structured_logging.py": [ + { + "type": "Base64 High Entropy String", + "filename": "tests/unit/test_structured_logging.py", + "hashed_secret": "0cb62954c5feaf5379bfb79b8e0087953ec49b9c", + "is_verified": false, + "line_number": 45 + }, + { + "type": "JSON Web Token", + "filename": "tests/unit/test_structured_logging.py", + "hashed_secret": "d6b66ddd9ea7dbe760114bfe9a97352a5e139134", + "is_verified": false, + "line_number": 50 + } + ], + "tests/unit/test_tenant_context.py": [ + { + "type": "Hex High Entropy String", + "filename": "tests/unit/test_tenant_context.py", + "hashed_secret": "c377074d6473f35a91001981355da793dc808ffd", + "is_verified": false, + "line_number": 350 + } + ], + "tests/unit/test_url_security.py.obsolete": [ + { + "type": "Basic Auth Credentials", + "filename": "tests/unit/test_url_security.py.obsolete", + "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", + "is_verified": false, + "line_number": 23 + } + ] + }, + "generated_at": "2025-12-11T05:17:25Z" +} From 5ac9f9214faf17e67b569b185e8c104bd0bf4943 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 16:53:22 +1100 Subject: [PATCH 2/5] chore: add dependabot for automated dependency updates Weekly updates for: - GitHub Actions (grouped minor/patch) - Python pip dependencies (grouped by type) - Rust Cargo dependencies (security team review) --- .github/dependabot.yml | 124 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..50b20fd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,124 @@ +# Dependabot configuration for cachekit-py +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 + +registries: + # No private registries - all deps are public + +updates: + # ───────────────────────────────────────────────────────────────────────── + # GitHub Actions + # Keep CI/CD supply chain current + # ───────────────────────────────────────────────────────────────────────── + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "America/Los_Angeles" + commit-message: + prefix: "ci" + labels: + - "dependencies" + - "github-actions" + reviewers: + - "cachekit-io/maintainers" + # Group minor/patch updates to reduce PR noise + groups: + actions-minor: + patterns: + - "*" + update-types: + - "minor" + - "patch" + + # ───────────────────────────────────────────────────────────────────────── + # Python (pip/uv) + # ───────────────────────────────────────────────────────────────────────── + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "America/Los_Angeles" + commit-message: + prefix: "chore" + labels: + - "dependencies" + - "python" + reviewers: + - "cachekit-io/maintainers" + # Ignore pre-releases unless explicitly opted in + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-prerelease"] + # Group by type to reduce PR noise + groups: + # Security-sensitive dependencies get individual PRs + # (not grouped - we want to review each) + python-dev: + patterns: + - "pytest*" + - "ruff" + - "basedpyright" + - "faker" + - "hypothesis" + update-types: + - "minor" + - "patch" + python-runtime: + patterns: + - "redis*" + - "pydantic*" + - "tenacity" + - "prometheus-client" + - "psutil" + update-types: + - "minor" + - "patch" + python-serialization: + patterns: + - "blake3" + - "msgpack" + - "orjson" + - "xxhash" + update-types: + - "minor" + - "patch" + + # ───────────────────────────────────────────────────────────────────────── + # Rust (Cargo) + # ───────────────────────────────────────────────────────────────────────── + - package-ecosystem: "cargo" + directory: "/rust" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "America/Los_Angeles" + commit-message: + prefix: "chore" + labels: + - "dependencies" + - "rust" + reviewers: + - "cachekit-io/maintainers" + - "cachekit-io/security" # Rust deps affect memory safety + # Security-critical crates get individual attention + # cachekit-core is pinned exactly, so dependabot won't touch it + groups: + rust-dev: + patterns: + - "criterion" + - "proptest" + - "divan" + - "fastrand" + - "iai-callgrind" + - "pprof" + - "ctor" + update-types: + - "minor" + - "patch" From 29dedd16c96e6f4ff7811b5e3c9861ca27a8736c Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 16:53:31 +1100 Subject: [PATCH 3/5] ci: add CodeQL SAST workflow Static analysis for security vulnerabilities: - Python analysis with security-extended queries - Runs on push, PR, and weekly schedule - SARIF results uploaded to Security tab + artifacts --- .github/workflows/codeql.yml | 100 +++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..71287d5 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,100 @@ +# CodeQL Static Application Security Testing (SAST) +# https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning-for-a-repository +# +# Analyzes Python and Rust code for: +# - Security vulnerabilities (injection, XSS, SSRF, etc.) +# - Code quality issues +# - Supply chain risks +# - Common programming errors +# +# Results appear in GitHub Security tab and as PR annotations. + +name: CodeQL + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + # Weekly deep scan on Sunday at 3am UTC + - cron: "0 3 * * 0" + workflow_dispatch: + # Manual trigger for ad-hoc security analysis + +permissions: + contents: read + security-events: write # Required for uploading SARIF results + actions: read # Required for workflow status + +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + + strategy: + fail-fast: false + matrix: + language: + - python + # Note: Rust support is limited in CodeQL + # We rely on cargo-audit, cargo-deny, and Miri for Rust security + # CodeQL language config + # https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Python setup for accurate analysis + - name: Set up Python + if: matrix.language == 'python' + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Python dependencies + if: matrix.language == 'python' + run: | + python -m pip install --upgrade pip + # Install dependencies so CodeQL can analyze import resolution + pip install -e ".[data]" || pip install -e . + + # Initialize CodeQL + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # Use security-extended for maximum coverage + # Options: security-extended, security-and-quality + queries: security-extended + # Config file for custom queries (optional) + # config-file: .github/codeql/codeql-config.yml + + # Autobuild attempts to build any compiled code + # For Python, this is largely a no-op but ensures imports resolve + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # Run CodeQL analysis + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{ matrix.language }}" + # Upload SARIF to GitHub Security tab + upload: true + # Also output SARIF for artifact storage + output: sarif-results + + # Archive SARIF for audit trail + - name: Upload SARIF artifact + uses: actions/upload-artifact@v4 + with: + name: codeql-sarif-${{ matrix.language }} + path: sarif-results + retention-days: 90 From 93871484250a783da94f4116cd9ae03ce5b9ef46 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 16:53:38 +1100 Subject: [PATCH 4/5] docs: enhance PR template with security checklist Added sections: - Security checklist (secrets, input validation, OWASP) - Dependency review requirements - Backward compatibility checklist - Performance change documentation --- .github/pull_request_template.md | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 896eb0e..dcd3cb2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,7 +11,35 @@ Why are these changes needed? What problem do they solve? - [ ] Bug fix (non-breaking) - [ ] New feature (non-breaking) - [ ] Breaking change +- [ ] Performance improvement - [ ] Documentation update +- [ ] Refactoring (no behavior change) +- [ ] CI/CD or tooling change + +--- + +## Security Checklist + +**For ALL PRs, verify:** + +- [ ] No secrets, credentials, or API keys in code or comments +- [ ] No hardcoded sensitive data (use env vars or config) +- [ ] User input is validated/sanitized where applicable +- [ ] Error messages don't leak sensitive information + +**For PRs touching security-critical paths** (`/rust/`, `/src/cachekit/serializers/`, `/src/cachekit/reliability/`, workflows): + +- [ ] Changes reviewed by security team (@cachekit-io/security) +- [ ] No new `unsafe` blocks without justification +- [ ] Cryptographic code uses audited libraries (no custom crypto) +- [ ] FFI boundaries maintain memory safety guarantees + +**For PRs adding/updating dependencies:** + +- [ ] Dependency is from trusted source with active maintenance +- [ ] No known CVEs (`pip-audit` / `cargo-audit` clean) +- [ ] License is compatible (MIT, Apache-2.0, BSD) +- [ ] Justified: not adding unnecessary attack surface --- @@ -38,6 +66,15 @@ Why are these changes needed? What problem do they solve? - [ ] Integration tests added/updated - [ ] Tests pass: `make test-critical` - [ ] No test regressions +- [ ] For performance changes: Benchmark results attached + +--- + +## Backward Compatibility + +- [ ] API is backward compatible OR breaking change is documented +- [ ] No removal of public APIs without deprecation period +- [ ] Migration path documented for breaking changes --- From 779e63086095a6c04aca90da7327e33e521ba62e Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 11 Dec 2025 16:55:11 +1100 Subject: [PATCH 5/5] ci: add GitHub App token support for release-please Enables optional GitHub App auth for branch protection bypass: - Falls back to GITHUB_TOKEN if APP_ID/APP_PRIVATE_KEY not set - Controlled via USE_APP_TOKEN repository variable --- .github/workflows/release-please.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index e9c23ed..0239df4 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -17,13 +17,23 @@ jobs: tag_name: ${{ steps.release.outputs.tag_name }} version: ${{ steps.release.outputs.version }} steps: + # Use GitHub App for token vending (avoids branch protection issues with GITHUB_TOKEN) + # If APP_ID/APP_PRIVATE_KEY not set, falls back to GITHUB_TOKEN + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v2 + if: ${{ vars.USE_APP_TOKEN == 'true' }} + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Run release-please id: release uses: googleapis/release-please-action@v4 with: manifest-file: .release-please-manifest.json config-file: release-please-config.json - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ steps.app-token.outputs.token || secrets.GITHUB_TOKEN }} build-wheels: name: Build wheels (${{ matrix.target }})