From db01bb5ec5bfa4a53565b5aeef40e5033fe071ae Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Wed, 11 Nov 2026 23:44:38 +0100 Subject: [PATCH] chore(licensing): SPDX headers, gitleaks allowlists and OpenSSF Scorecard SPDX headers now sit in the first 30 lines of every tracked source file (99.84% -> 100% of 1251 files), in the style the repository already uses; the translation catalogues are covered by REUSE.toml. .gitleaks.toml keeps the default gitleaks rules and allows, per named file and rule, the findings that are test fixtures, seed identifiers or documented default logins, each with the reason. Adds the OpenSSF Scorecard workflow (actions pinned by commit SHA) and gives the workflows whose token needs are known a read-only top-level permission, with the write grants on the jobs that need them. Assisted-by: ClaudeCode:claude-opus-5-5 --- .github/workflows/branch-policy.yml | 3 ++ .github/workflows/documentation.yml | 6 ++++ .github/workflows/issue-triage.yml | 6 ++++ .github/workflows/openspec-sync.yml | 6 ++++ .github/workflows/release.yml | 12 +++++++ .github/workflows/scorecard.yml | 52 +++++++++++++++++++++++++++ .github/workflows/sync-to-beta.yml | 6 ++++ .gitleaks.toml | 55 +++++++++++++++++++++++++++++ phpstan-bootstrap.php | 3 ++ stylelint.config.js | 4 +++ 10 files changed, 153 insertions(+) create mode 100644 .github/workflows/scorecard.yml create mode 100644 .gitleaks.toml diff --git a/.github/workflows/branch-policy.yml b/.github/workflows/branch-policy.yml index 1dca5b78c..d6723440a 100644 --- a/.github/workflows/branch-policy.yml +++ b/.github/workflows/branch-policy.yml @@ -4,6 +4,9 @@ on: pull_request: branches: [main, beta, development] +permissions: + contents: read + jobs: check-source-branch: name: Branch Policy Check diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 1f7ccf072..b3f847639 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -12,8 +12,14 @@ on: pull_request: branches: [development] +permissions: + contents: read + jobs: deploy: + permissions: + contents: write + packages: write uses: ConductionNL/.github/.github/workflows/documentation.yml@main # A reusable workflow receives NO secrets by default. Without this block the # callee's publish step finds CF_API_TOKEN empty, skips itself on its own diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index a122c1601..30c2dbed1 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -10,8 +10,14 @@ on: type: boolean default: true +permissions: + contents: read + jobs: triage: + permissions: + issues: write + contents: read uses: ConductionNL/.github/.github/workflows/issue-triage.yml@main with: app-name: launchpad diff --git a/.github/workflows/openspec-sync.yml b/.github/workflows/openspec-sync.yml index cd5de2c3a..ef24c8790 100644 --- a/.github/workflows/openspec-sync.yml +++ b/.github/workflows/openspec-sync.yml @@ -42,8 +42,14 @@ on: paths: ['openspec/**'] workflow_dispatch: +permissions: + contents: read + jobs: sync: + permissions: + issues: write + contents: read uses: ConductionNL/.github/.github/workflows/openspec-sync.yml@main with: app-name: launchpad diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1a4950612..02ffc4b1b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,9 +27,15 @@ concurrency: group: release-${{ github.ref_name }} cancel-in-progress: false +permissions: + contents: read + jobs: unstable: if: github.ref == 'refs/heads/development' + permissions: + contents: write + pull-requests: write uses: ConductionNL/.github/.github/workflows/release.yml@main with: release-type: unstable @@ -38,6 +44,9 @@ jobs: beta: if: github.ref == 'refs/heads/beta' + permissions: + contents: write + pull-requests: write uses: ConductionNL/.github/.github/workflows/release.yml@main with: release-type: beta @@ -46,6 +55,9 @@ jobs: stable: if: github.ref == 'refs/heads/main' + permissions: + contents: write + pull-requests: write uses: ConductionNL/.github/.github/workflows/release.yml@main with: release-type: stable diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 000000000..974fea8be --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2026 Conduction B.V. +# SPDX-License-Identifier: EUPL-1.2 + +# OpenSSF Scorecard: rates this repository's supply-chain practices and +# publishes the result to the public Scorecard API and the Security tab. +name: Scorecard supply-chain security + +on: + branch_protection_rule: + schedule: + - cron: '30 4 * * 1' + push: + branches: [main] + workflow_dispatch: + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Upload the results to code scanning. + security-events: write + # Publish the results and get a badge (OIDC token for the Scorecard API). + id-token: write + contents: read + actions: read + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Run analysis + uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: Upload artifact + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + - name: Upload to code scanning + uses: github/codeql-action/upload-sarif@33d7b85da1a04171e211befe2c739303b9a4c066 # v4.39.3 + with: + sarif_file: results.sarif diff --git a/.github/workflows/sync-to-beta.yml b/.github/workflows/sync-to-beta.yml index 76a442693..62fd631be 100644 --- a/.github/workflows/sync-to-beta.yml +++ b/.github/workflows/sync-to-beta.yml @@ -5,6 +5,12 @@ on: branches: - development +permissions: + contents: read + jobs: sync: + permissions: + contents: write + pull-requests: write uses: ConductionNL/.github/.github/workflows/sync-to-beta.yml@main diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 000000000..c519518f8 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,55 @@ +# gitleaks configuration: the default rules, plus allowlists for findings +# that are not secrets. Each allowlist names the exact files and only the +# rules that fire there, so anything else in those files is still reported. + +[extend] +useDefault = true + +[[allowlists]] +description = "Documentation examples: the default admin:admin login of the local development and demo containers." +targetRules = ["curl-auth-user"] +paths = [ + '''(^|/)docs/Installation/demo\-environment\.md$''', +] + +[[allowlists]] +description = "Spec scenario: an example public-share token in a Given/When/Then step, not a credential." +targetRules = ["generic-api-key"] +paths = [ + '''(^|/)openspec/changes/archive/2026\-06\-14\-dashboard\-public\-share/specs/dashboard\-public\-share/spec\.md$''', +] + +[[allowlists]] +description = "Smoke-test notes: curl logins of the throwaway local test users (admin, user, alice)." +targetRules = ["curl-auth-user"] +paths = [ + '''(^|/)openspec/changes/archive/2026\-06\-14\-role\-based\-content/smoke\.md$''', +] + +[[allowlists]] +description = "Spec example: a truncated sample JWT in an SDK usage snippet, not a credential." +targetRules = ["generic-api-key"] +paths = [ + '''(^|/)openspec/changes/embedded\-analytics/specs/sdk\-and\-rendering\.md$''', +] + +[[allowlists]] +description = "Design note: a curl example with a user:app-password placeholder." +targetRules = ["curl-auth-user"] +paths = [ + '''(^|/)openspec/changes/governance\-rest\-api\-reference/design\.md$''', +] + +[[allowlists]] +description = "Spec scenario: an example public-share token in a Given/When/Then step, not a credential." +targetRules = ["generic-api-key"] +paths = [ + '''(^|/)openspec/specs/dashboard\-public\-share/spec\.md$''', +] + +[[allowlists]] +description = "E2E seed script: curl login built from the ADMIN_USER/ADMIN_PASSWORD environment variables, not a literal." +targetRules = ["curl-auth-user"] +paths = [ + '''(^|/)tests/e2e/seed\.sh$''', +] diff --git a/phpstan-bootstrap.php b/phpstan-bootstrap.php index b473c89c3..d9fca55dd 100644 --- a/phpstan-bootstrap.php +++ b/phpstan-bootstrap.php @@ -2,6 +2,9 @@ /** * PHPStan bootstrap file - registers OCP autoloader for static analysis. + * + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 */ $autoloader = require __DIR__ . '/vendor/autoload.php'; diff --git a/stylelint.config.js b/stylelint.config.js index dbe67ece4..8cc0ba193 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -1,3 +1,7 @@ +/** + * SPDX-FileCopyrightText: 2026 Conduction B.V. + * SPDX-License-Identifier: EUPL-1.2 + */ module.exports = { extends: '@nextcloud/stylelint-config', rules: {