Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

# Path-based auto-labelling for A/* area labels.
# Used by .github/workflows/auto-label-areas.yml via actions/labeler@v5.
# One PR can match multiple areas (e.g. modules + testing).

"A/hardening":
- changed-files:
- any-glob-to-any-file:
- "modules/anssi/**"
- "modules/auditd.nix"

"A/auth":
- changed-files:
- any-glob-to-any-file:
- "modules/security-keys.nix"
- "modules/pam/**"
- "modules/ssh-tpm-agent.nix"
- "modules/superadmins/**"
- "modules/admins/**"

"A/encryption":
- changed-files:
- any-glob-to-any-file: "modules/filesystems/**"

"A/secure-boot":
- changed-files:
- any-glob-to-any-file: "modules/bootloader.nix"

"A/networking":
- changed-files:
- any-glob-to-any-file:
- "modules/networking.nix"
- "modules/networkmanager-events.nix"
- "modules/vpn/**"
- "modules/http-proxy/**"
- "modules/bastion/**"

"A/modules":
- changed-files:
- any-glob-to-any-file:
- "modules/chromium/**"
- "modules/graphical-interface/**"
- "modules/tools/**"
- "modules/console.nix"
- "modules/shells.nix"
- "modules/pki.nix"

"A/nixos":
- changed-files:
- any-glob-to-any-file:
- "lib/**"
- "default.nix"
- "shell.nix"
- "npins/**"
- "pkgs/overlay.nix"

"A/hardware":
- changed-files:
- any-glob-to-any-file: "hardware/**"

"A/docs":
- changed-files:
- any-glob-to-any-file:
- "docs/**"
- "*.md"
- "LICENSES/**"

"A/testing":
- changed-files:
- any-glob-to-any-file:
- "tests/**"
- ".github/workflows/securix-testsuite.yaml"
- "workflows/**"

"A/lifecycle":
- changed-files:
- any-glob-to-any-file:
- "modules/updates/**"
- "modules/self.nix"
- "modules/distribution.nix"

"A/infra":
- changed-files:
- any-glob-to-any-file:
- ".github/workflows/**"
- "config.yml"
- "statix.toml"
- ".pre-commit-config.yaml"
27 changes: 27 additions & 0 deletions .github/workflows/auto-label-areas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

name: "Auto-label: areas"

on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review]

permissions: {}

jobs:
label:
# pull_request_target is safe here: labeler is pinned, configuration is
# read from the base branch, and the action only uses the GitHub API.
if: github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7
with:
configuration-path: .github/labeler.yml
sync-labels: false
dot: false
133 changes: 133 additions & 0 deletions .github/workflows/auto-label-status.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

name: "Auto-label: status"

on:
pull_request_target: # zizmor: ignore[dangerous-triggers] - safe: pinned action, no secrets, same-repo only
types: [opened, reopened, synchronize, ready_for_review]
pull_request_review:
types: [submitted]
pull_request_review_comment:
types: [created]
issues:
types: [opened]

permissions: {}

jobs:
pr-opened:
# pull_request_target is safe here: github-script is pinned, no secrets are
# used, and the action only calls the GitHub API to manage labels.
if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository
permissions:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0
with:
script: |
const pr = context.payload.pull_request;
if (!pr) return;
const issue_number = pr.number;
const repo = context.repo;
const labels = pr.labels.map(l => l.name);
const has = n => labels.includes(n);

// On open/sync, ensure awaiting-maintainers is set and awaiting-author is cleared
// This implements: new PR -> awaiting-maintainers
if (!has('status: awaiting-maintainers') && !has('status: ready-to-merge') && !has('status: awaiting smoke testing') && !has('status: blocked')) {
await github.rest.issues.addLabels({ ...repo, issue_number, labels: ['status: awaiting-maintainers'] });
}
if (has('status: awaiting-author')) {
try { await github.rest.issues.removeLabel({ ...repo, issue_number, name: 'status: awaiting-author' }); } catch(e) {}
}
// New author push after review -> flip back from awaiting-author is handled here via synchronize
// If PR was in awaiting-author and author pushed, the above remove + add covers it

review:
if: github.event_name == 'pull_request_review' || github.event_name == 'pull_request_review_comment'
permissions:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0
with:
script: |
const review = context.payload.review;
const pr = context.payload.pull_request || review?.pull_request;
if (!pr || !review) return;
const issue_number = pr.number;
const repo = context.repo;
const assoc = review.author_association; // OWNER, MEMBER, COLLABORATOR, etc.
const isMaintainer = ['OWNER','MEMBER'].includes(assoc);
if (!isMaintainer) return;

const state = review.state; // approved, changes_requested, commented
// Fetch current labels (payload may be stale)
const { data: cur } = await github.rest.issues.get({ ...repo, issue_number });
const has = n => cur.labels.some(l => l.name === n);

if (state === 'changes_requested' || (state === 'commented' && has('status: awaiting-maintainers'))) {
// Maintainer reviewed -> awaiting-author
if (has('status: awaiting-maintainers')) {
try { await github.rest.issues.removeLabel({ ...repo, issue_number, name: 'status: awaiting-maintainers' }); } catch(e) {}
}
if (!has('status: awaiting-author') && !has('status: blocked')) {
await github.rest.issues.addLabels({ ...repo, issue_number, labels: ['status: awaiting-author'] });
}
}
if (state === 'approved') {
if (has('status: awaiting-author')) {
try { await github.rest.issues.removeLabel({ ...repo, issue_number, name: 'status: awaiting-author' }); } catch(e) {}
}
// ready-to-merge is set after CI checks pass; we only ensure not stuck in awaiting-*
// If checks already green, mark ready; otherwise awaiting-maintainers will be set on next sync
}

ci-result:
# workflow_run is safe here: github-script is pinned, no secrets are used,
# and the action only calls the GitHub API to manage labels. We only act on
# PRs from the same repository to avoid processing fork-sourced workflow runs.
if: github.event_name == 'workflow_run' && github.event.workflow_run.head_repository.full_name == github.repository

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is workflow_run missing from on:?

permissions:
pull-requests: write
issues: write
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@d746ffe35508b1917358783b479e04febd2b8f71 # v9.0.0
with:
script: |
const run = context.payload.workflow_run;
if (!run) return;
// Only act on PRs
const prs = run.pull_requests;
if (!prs || prs.length === 0) return;
for (const pr of prs) {
const issue_number = pr.number;
const { data: cur } = await github.rest.issues.get({ ...context.repo, issue_number });
const has = n => cur.labels.some(l => l.name === n);
if (run.conclusion === 'failure' || run.conclusion === 'timed_out') {
if (!has('status: awaiting-ci')) {
await github.rest.issues.addLabels({ ...context.repo, issue_number, labels: ['status: awaiting-ci'] });
}
} else if (run.conclusion === 'success') {
if (has('status: awaiting-ci')) {
try { await github.rest.issues.removeLabel({ ...context.repo, issue_number, name: 'status: awaiting-ci' }); } catch(e) {}
}
// If PR is approved and CI just turned green, promote to ready-to-merge
// Check reviews: last review approved?
const { data: reviews } = await github.rest.pulls.listReviews({ ...context.repo, pull_number: issue_number, per_page: 20 });
const last = [...reviews].reverse().find(r => ['OWNER','MEMBER'].includes(r.author_association));
if (last && last.state === 'APPROVED' && !has('status: ready-to-merge') && !has('status: blocked')) {
await github.rest.issues.addLabels({ ...context.repo, issue_number, labels: ['status: ready-to-merge'] });
if (has('status: awaiting-maintainers')) {
try { await github.rest.issues.removeLabel({ ...context.repo, issue_number, name: 'status: awaiting-maintainers' }); } catch(e) {}
}
if (has('status: awaiting-author')) {
try { await github.rest.issues.removeLabel({ ...context.repo, issue_number, name: 'status: awaiting-author' }); } catch(e) {}
}
}
}
}
32 changes: 21 additions & 11 deletions .github/workflows/securix-cd-docs.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
permissions:
contents: write
id-token: write
pages: write
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

name: '[Sécurix] Publish documentation'

on:
workflow_dispatch:
push:
branches:
- main

permissions: {}

concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: false

jobs:
publish_docs:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
contents: read
id-token: write
pages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- uses: samueldr/lix-gha-installer-action@f526e761e1ad201b0f4231f61a2a569f17bcc2ac # main
- name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
Expand All @@ -25,10 +42,3 @@ jobs:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
name: '[Sécurix] Publish documentation'
on:
workflow_dispatch:
push:
branches:
- main

22 changes: 16 additions & 6 deletions .github/workflows/securix-check-formatting.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

name: '[Sécurix] Formatting check'

on:
pull_request:
push:
branches:
- main

permissions: {}

jobs:
reuse_lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- uses: samueldr/lix-gha-installer-action@f526e761e1ad201b0f4231f61a2a569f17bcc2ac # main
- name: Check for statix
run: nix-shell --run 'statix check --config statix.toml'
- name: Check for formatting
run: nix-shell --run 'nixfmt -sc $(find . -name "*.nix" -not -path "./npins/*" -not -path "./lib/default.nix")'
name: '[Sécurix] Formatting check'
on:
pull_request:
push:
branches:
- main
22 changes: 16 additions & 6 deletions .github/workflows/securix-check-licensing.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

name: '[Sécurix] REUSE Licensing conformance'

on:
pull_request:
push:
branches:
- main

permissions: {}

jobs:
reuse_lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- uses: samueldr/lix-gha-installer-action@f526e761e1ad201b0f4231f61a2a569f17bcc2ac # main
- name: Check for REUSE compliance
run: nix-shell --run 'reuse --root . lint'
name: '[Sécurix] REUSE Licensing conformance'
on:
pull_request:
push:
branches:
- main
18 changes: 15 additions & 3 deletions .github/workflows/securix-ci-docs.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
# SPDX-FileCopyrightText: 2026 Ryan Lahfa <ryan.lahfa.ext@numerique.gouv.fr>
#
# SPDX-License-Identifier: MIT

name: '[Sécurix] Test the docs'

on:
pull_request:

permissions: {}

concurrency:
group: preview-pages-${{ github.ref }}
cancel-in-progress: true

jobs:
build_and_preview_manual_docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
persist-credentials: false
- uses: samueldr/lix-gha-installer-action@f526e761e1ad201b0f4231f61a2a569f17bcc2ac # main
- name: Build the manual documentation
run: nix-build -A docs.all
name: '[Sécurix] Test the docs'
on:
pull_request:

Loading
Loading