Skip to content

Security: yanix2445/setup-macos

Security

SECURITY.md

Politique de sécurité

Document de référence pour les chercheurs en sécurité, auditeurs, utilisateurs en environnement sensible, et contributeurs. Pour signaler une vulnérabilité, va directement à Signaler une vulnérabilité.


📑 Sommaire


⚡ TL;DR

  • Vulnérabilité ?GitHub Security Advisory privéjamais d'issue publique
  • Email backup : yanis@yanixlabs.com
  • SLA accusé de réception : 72 h
  • Versions supportées : 1.x.y (latest minor uniquement)
  • SLSA Build Level : 3 (provenance signée OIDC, build hosted, transparency log)
  • Vérification user : gh attestation verify ~/.local/bin/setup-macos --owner yanix2445

✅ Versions supportées

Ce projet adhère à SemVer. Les correctifs de sécurité sont publiés selon la politique suivante :

Branche Statut Correctifs sécurité EOL
1.x.y (latest minor) Active Oui — patch immédiat sur la dernière mineure
1.x-1.y (n-1 minor) 🟡 Maintenance limitée Critique uniquement (CVSS ≥ 9.0), 30 j EOL à la sortie de 1.x+1
< 1.0.x (pre-V1) Non supportée Aucun EOL au tag v1.0.0

Vérifier ta version :

setup-macos --version
# Si < dernière disponible → setup-macos update

Politique de rétroportage : un fix de sécurité critique sur la branche active déclenche automatiquement un patch sur la n-1 durant la fenêtre de maintenance. Au-delà, pas de garantie : il est de la responsabilité de l'utilisateur de migrer vers la branche active.


🔒 Signaler une vulnérabilité

N'ouvre JAMAIS d'issue publique pour une vulnérabilité. Cela exposerait des utilisateurs avant qu'un correctif soit disponible.

Canaux acceptés (par ordre de préférence)

  1. GitHub Security Advisory privé ⭐ recommandé
  2. Email : yanis@yanixlabs.com
    • Sujet préfixé [security] setup-macos: ...
    • Réponse sous 72 h ouvrées

Format d'un rapport efficace

Un rapport actionnable contient a minima :

Champ Détail attendu
Type Code execution, privilege escalation, info disclosure, DoS, supply chain, etc.
Composant affecté Fichier + ligne(s) si possible (ex : cmd/setup-macos/update.go:213 atomicReplace)
Versions concernées Plage de versions vulnérables (<= 1.2.0, >= 1.0.0, etc.)
Pré-conditions Ce qu'il faut pour exploiter (réseau, accès local, sudo, etc.)
PoC minimal Étapes reproductibles + payload si applicable
Impact Qu'est-ce qu'un attaquant obtient ? (RCE, fuite de données, persistance, etc.)
Score CVSS estimé Optionnel mais aide à prioriser (calculateur 3.1)
Suggestion de fix Optionnel — bienvenu si tu en as une

Ce qui n'est pas une vulnérabilité

  • Un crash sur input malformé qui nécessite un accès local explicite → c'est un bug normal, ouvre une issue publique
  • Une feature désactivée par défaut qu'on peut activer dangereusement avec SKIP_VERIFY=1 → c'est documenté
  • Un soucis de qualité de code sans impact exploitable → PR bienvenue
  • Un comportement de Homebrew lui-même → upstream (brew)

🤝 Politique de divulgation coordonnée

Timeline standard

J+0    : Réception du rapport
J+3    : Accusé de réception (max 72 h)
J+7    : Triage initial, validation de la repro
J+14   : Plan de fix proposé au reporter
J+30   : Patch prêt, advisory en draft
J+30+x : Coordination avec le reporter sur la date de release
J+R    : Release publique + advisory + CVE (si applicable)
J+R+30 : Embargo levé, tous les détails techniques publiables

Embargo

  • Par défaut : pas d'embargo formel. La divulgation est publique au moment de la release du patch.
  • Sur demande du reporter : embargo jusqu'à J+90 maximum, le temps que les usagers majeurs puissent mettre à jour.

Crédit

  • Le reporter est cité dans l'advisory GitHub, dans le CHANGELOG.md et dans le commit message — sauf demande contraire de sa part.
  • Pas de bug bounty financier (projet open-source perso). Reconnaissance publique uniquement.

CVE

  • Assignation automatique via GitHub pour les vulnérabilités validées (CVSS ≥ 4.0)
  • Le numéro CVE est inclus dans l'advisory dès qu'il est attribué

🎯 Modèle de menace

Surface d'attaque

┌─────────────────────────────────────────────────────────────────┐
│                       SURFACE D'ATTAQUE                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  📥 Distribution        ┐                                       │
│   ├─ install.sh         ├─ download depuis github.com          │
│   ├─ setup-macos update ┘                                       │
│                                                                 │
│  📦 Inputs                                                      │
│   ├─ catalog.yaml       ─ YAML user-modifiable                 │
│   ├─ profiles.yaml      ─ YAML user-modifiable                 │
│   ├─ Args CLI           ─ ID outils, paths                     │
│   ├─ Env vars           ─ INSTALL_DIR, SKIP_VERIFY, VERSION    │
│   └─ Réponses HTTP      ─ GitHub API, releases assets          │
│                                                                 │
│  ⚙️ Subprocess                                                  │
│   ├─ brew install       ─ via exec.CommandContext              │
│   ├─ /bin/bash install  ─ script Homebrew officiel             │
│   ├─ curl / shasum      ─ install.sh                           │
│   └─ git clone          ─ runCustomInstall pour p10k           │
│                                                                 │
│  💾 Persistance                                                 │
│   ├─ ~/.local/bin/      ─ binaire installé                     │
│   ├─ ~/.local/share/    ─ catalog + profils + marker           │
│   ├─ ~/.zprofile/.zshrc ─ append PATH + brew shellenv          │
│   └─ /opt/homebrew/     ─ délégué à Homebrew                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Frontières de confiance

Frontière Côté confiance Côté non-confiance
Réseau Binaire local github.com, releases assets, GitHub API
Filesystem Binaire propre YAML user-modifiable, fichiers téléchargés
Process setup-macos (notre code) brew, bash, scripts d'install upstream
User User local Args CLI fournis par d'autres scripts (CI, hostile)
OS macOS sain Configs malveillantes (PATH hijacked, etc.)

Principe : tout ce qui passe une frontière de confiance doit être vérifié (SHA256, attestation, validation YAML, sanitization) ou isolé (subprocess avec args explicites, pas de shell injection).

Acteurs envisagés

Acteur Capacité Motif
Script kiddie Lance des PoC publics Curiosité, défacement
Attaquant réseau (MITM) Intercepte le trafic HTTP de la victime Backdoor le binaire
Repo squatter Crée setup-macos-x ou setup-mac0s typo Phishing
Maintainer hostile (compromis) Push du code malveillant sur le repo officiel Backdoor large échelle
Dépendance compromise Auteur d'une dep Go push une version backdorée Supply chain attack
User local Modifie YAML ou env vars Escalade de privilèges (très limité ici)

Vecteurs couverts

# Vecteur Mitigation en place
1 MITM sur download install.sh install.sh télécharge SHA256SUMS et vérifie chaque fichier via shasum -a 256 -c. Refus d'installer si fichier corrompu ou SHA256SUMS manquant.
2 MITM sur setup-macos update update.go:downloadAsset télécharge SHA256SUMS, parse via parseSHA256SUMS, calcule sha256.Sum256 et compare. Le binaire n'est jamais écrit sur disque avant validation.
3 Substitution combinée binaire + SHA256SUMS Les deux assets sont signés via GitHub Artifact Attestations (OIDC, sigstore, transparency log Rekor). Vérifiable via gh attestation verify.
4 Binaire de mise à jour cassé / backdooré healthCheck() après atomicReplace lance <new-binary> --version et compare avec la version attendue. Échec → rollback automatique depuis .bak.
5 Compromise de tag GitHub Actions Toutes les actions tierces (checkout, setup-go, golangci-lint-action, attest-build-provenance, action-gh-release) sont pinnées par SHA commit, pas par tag mutable.
6 Catalogue YAML malicieux internal/catalog/loader.go:validateCatalog rejette : champs requis manquants, IDs dupliqués. internal/catalog/loader.go:validateProfiles rejette : profils vides, IDs dupliqués, refs croisées invalides. Validation au load, fail-loud.
7 Hang infini d'un subprocess brew internal/brew/check.go:DefaultCheckTimeout = 5 * time.Second. Toutes les invocations passent par exec.CommandContext. Aucun risque de freeze TUI.
8 Race condition / send on closed channel defer wg.Wait() AVANT defer close(out) (LIFO) dans internal/brew/install.go:Install. Test régression TestInstall_ContextCancelledMidLoop_NoChannelPanic (50 itérations stress, exécuté avec -race en CI).
9 Push direct sur main contournant la review Branch protection sur main : PR obligatoire, status check Lint + Test + Build requis, linear history, force-push interdit, enforce_admins: true (le mainteneur lui-même ne peut pas contourner).
10 Build non reproductible -trimpath + -ldflags "-s -w" + Go pinné 1.26.x + MACOSX_DEPLOYMENT_TARGET=11.0. Un rebuild local produit un binaire byte-pour-byte identique à la release.
11 Telemetry / phone home non documenté Aucunegrep -r "telemetry|analytics" . retourne vide. Pas de call HTTP sortant hors github.com (API releases + download).
12 Permissions excessives en CI Workflow release.yml : contents: write, id-token: write, attestations: write uniquement, scopées au job release. Le workflow ci.yml est contents: read strict.

Vecteurs non couverts

Vecteur Pourquoi pas Mitigation côté utilisateur
Compte GitHub yanix2445 compromis Hors scope d'un mainteneur solo. Mitigation upstream impossible sans MFA hardware-backed + signing keys, ce qui change l'OPSEC du projet. Avant toute install/update : gh attestation verify et vérifier que l'identité OIDC dans l'attestation est bien https://github.com/yanix2445/setup-macos.
Vérification d'attestation pas automatique dans install/update Roadmap V1.1. L'implémentation propre demande de bundler la lib cosign en Go, non-trivial. Lancer manuellement gh attestation verify ~/.local/bin/setup-macos --owner yanix2445 après chaque install.
Repository spoofing / typosquatting install.sh est hardcodé sur yanix2445/setup-macos, mais ne protège pas si un user copie une URL d'un fork malveillant. Toujours utiliser l'URL canonique depuis le README officiel. Vérifier l'attestation.
Compromission de Homebrew amont On délègue brew install à Homebrew lui-même. Sa sécurité est leur scope. Homebrew a son modèle de menace et un programme de signalement.
Compromission d'une dépendance Go indirecte go.mod est pinné et go.sum vérifie les hashes, mais govulncheck n'est pas (encore) en CI. Roadmap V1.1. Lancer govulncheck ./... régulièrement (cf. Pour les utilisateurs).
Apple Gatekeeper warning sur download manuel Binaire pas signé Apple Developer ID (99 €/an, hors scope projet perso). Install via curl | bash officiel (curl ne pose pas l'attribut quarantine) — pas de warning.
TOCTOU sur ~/.local/bin/setup-macos entre check et exec Théorique, impact local uniquement, attaquant local déjà préfix du setup-macos foutu. Garder ~/.local/bin/ avec des permissions user-only (chmod 755).
Empoisonnement de ~/.zprofile/~/.zshrc par un autre process Hors scope, le code n'append qu'avec un sentinel commenté. Utiliser un user macOS dédié pour les setups expérimentaux (VM, autre compte).

🏛️ Architecture de sécurité

Supply chain & SLSA

setup-macos est conforme SLSA Build Level 3 :

Niveau SLSA Exigence Status
L1 Build automatisé scripté ✅ GitHub Actions
L2 Build sur infrastructure hébergée + version control ✅ macos-14 runner, GitHub
L3 Provenance signée, non forgeable par les builders ✅ Artifact Attestations OIDC
L4 Build hermétique, deux builders indépendants ⚠️ Single hosted runner (acceptable)

Provenance : chaque release est accompagnée d'une attestation in-toto signée via Sigstore (cosign + Fulcio + Rekor). La signature est ancrée dans un transparency log public.

Comment vérifier :

gh attestation verify ~/.local/bin/setup-macos --owner yanix2445 --format json

L'output JSON contient :

  • subject.name : nom du binaire attesté
  • predicate.buildDefinition.externalParameters.workflow.repository : repo source
  • predicate.runDetails.builder.id : identité du runner (https://github.com/actions/runner)

Vérification d'intégrité

install.sh

# 1. Téléchargement des assets dans un workspace temporaire (mktemp -d, trap cleanup)
curl --max-time 60 ${BASE_URL}/${BIN_ASSET}   -o $WORK_DIR/${BIN_ASSET}
curl --max-time 30 ${BASE_URL}/catalog.yaml   -o $WORK_DIR/catalog.yaml
curl --max-time 30 ${BASE_URL}/profiles.yaml  -o $WORK_DIR/profiles.yaml

# 2. Téléchargement du SHA256SUMS (refus d'install si absent)
curl --max-time 30 ${BASE_URL}/SHA256SUMS -o $WORK_DIR/SHA256SUMS || err "SHA256SUMS introuvable"

# 3. Vérification SHA256 (refus d'install si mismatch)
(cd $WORK_DIR && shasum -a 256 --ignore-missing -c SHA256SUMS) || err "Hash mismatch"

# 4. Installation atomique : mv seulement après validation complète
mv $WORK_DIR/${BIN_ASSET}  $INSTALL_DIR/setup-macos

Escape hatch : SKIP_VERIFY=1 bash install.sh désactive la vérification — affiche un warning. À réserver aux cas exceptionnels (releases pre-V1, debugging).

setup-macos update (cmd/setup-macos/update.go)

// 1. Download dans des []byte en mémoire (pas sur disque avant validation)
binData,  _ := downloadAsset(latest.TagName, assetName)
catData,  _ := downloadAsset(latest.TagName, "catalog.yaml")
profData, _ := downloadAsset(latest.TagName, "profiles.yaml")

// 2. Download SHA256SUMS (refus si missing)
sumsData, err := downloadAsset(latest.TagName, "SHA256SUMS")
if err != nil {
    return fmt.Errorf("SHA256SUMS introuvable : refus d'installer un binaire non vérifié")
}

// 3. Parse + verify chaque fichier (SHA256 comparé en constant-time)
sums, _ := parseSHA256SUMS(sumsData)
for _, c := range checks {
    want, ok := sums[c.name]
    if !ok { return fmt.Errorf("hash manquant pour %s", c.name) }
    got := sha256.Sum256(c.data)
    if hex.EncodeToString(got[:]) != want {
        return fmt.Errorf("hash mismatch pour %s — fichier corrompu ou compromis", c.name)
    }
}

// 4. Atomic replace + health check
atomicReplace(exe, binData, true)
if err := healthCheck(exe, latestVer); err != nil {
    // Rollback automatique depuis .bak
    os.Rename(exe+".bak", exe)
    return fmt.Errorf("nouveau binaire non fonctionnel : rollback effectué")
}

Build reproductible

Toutes les releases respectent :

GOOS=darwin GOARCH=arm64 \
  MACOSX_DEPLOYMENT_TARGET=11.0 \
  go build -trimpath -ldflags "-s -w -X main.version=<TAG>" \
  -o setup-macos-darwin-arm64 ./cmd/setup-macos

Drapeaux clés :

Flag Effet sur la reproductibilité
-trimpath Supprime les chemins absolus du build (sinon /Users/runner/work/... pollue le binaire)
-ldflags "-s -w" Strip symboles + DWARF (deterministe, plus petit)
-X main.version=<TAG> Injection version depuis le tag git (pas de drift code/release)
MACOSX_DEPLOYMENT_TARGET=11.0 Fixe le SDK macOS visé (sinon dépend du runner)
Go 1.26.x pinné Match avec go.mod

Vérifier que ton rebuild local match la release :

make release-build                                # build local
shasum -a 256 bin/setup-macos-darwin-arm64        # hash local

# Compare avec :
curl -fsSL https://github.com/yanix2445/setup-macos/releases/download/v1.2.0/SHA256SUMS \
  | grep setup-macos-darwin-arm64

Les deux hashes doivent être strictement égaux. Sinon, il y a soit un environnement de build différent, soit un acte malveillant.

Atomicité & rollback

Toute opération destructive est atomique + rollback-able :

Opération Stratégie Cf. code
Install fresh Download en mktemp -d, vérif SHA256, mv final (atomique POSIX) install.sh:69-95
Update binaire os.CreateTemp → write → chmod → backup .bakos.Rename atomique cmd/setup-macos/update.go atomicReplace
Update foire Restore .bak → erreur explicite ("rollback effectué") idem
Health check fail post-update Restore .bak automatique → erreur explicite idem
Ctrl+C pendant install trap cleanup EXIT INT TERM supprime le workspace temporaire install.sh:36-39
Ctrl+C pendant TUI install ctx.Done() propagé aux subprocess brew install via exec.CommandContext internal/brew/install.go:Install

🛡️ Pratiques de développement sécurisé (Go)

Aligné sur les Secure Coding Guidelines de Go et OWASP Go Secure Coding.

1. Validation d'inputs

Tout input qui franchit une frontière de confiance est validé avant utilisation :

// catalog/loader.go — YAML validé strict
func validateCatalog(c *Catalog) error {
    for _, t := range c.Tools {
        if t.ID == "" { return fmt.Errorf("outil : id manquant") }
        if t.Check == "" { return fmt.Errorf("outil %q : check manquant", t.ID) }
        // ...
    }
}

// brew/check.go — spec check parsée strictement
parts := strings.SplitN(check, ":", 2)
if len(parts) != 2 { return false }  // refus silencieux des formats invalides

// update.go — hash comparé contre l'attendu
if hex.EncodeToString(got[:]) != want {
    return fmt.Errorf("hash mismatch")
}

2. Gestion d'erreurs explicite

  • Aucun panic() en code de production (cherche : grep -r "panic(" cmd/ internal/ → vide hors tests)
  • Aucun log.Fatal() (idem)
  • Tout error est propagé avec fmt.Errorf("contexte : %w", err) pour préserver la chaîne errors.Is/errors.As
  • Les rares _ = sont justifiés en commentaire ou concernent des defer Close() où l'erreur n'apporte rien

3. Context propagation

Toute opération bloquante prend un context.Context en premier paramètre :

func Install(ctx context.Context, tools []catalog.Tool, concurrency int) <-chan ProgressMsg
func IsInstalledCtx(ctx context.Context, check string) bool
func RunFirstTimeBootstrap(ctx context.Context) error

Subprocess : toujours exec.CommandContext(ctx, ...), jamais exec.Command(...). Permet à un Ctrl+C utilisateur de tuer proprement les processus enfants.

4. Concurrence safe

Patterns appliqués dans internal/brew/install.go (worker pool) :

  • Sémaphore borné (chan struct{}) au lieu de fork sans limite
  • defer wg.Wait() AVANT defer close(channel) (LIFO) — évite panic: send on closed channel
  • select { case <-ctx.Done(): return } dans toute opération bloquante d'une goroutine
  • Race detector activé en CI (go test -race) — la CI rejette si race détectée

5. Pas de shell injection

Tous les subprocess sont invoqués avec args séparés, pas via sh -c <chaîne> interpolée :

// ✅ Bon
exec.CommandContext(ctx, "brew", "install", tool.Brew)

// ❌ Mauvais (commande interpolée — risque d'injection si tool.Brew vient d'un input non vérifié)
exec.CommandContext(ctx, "sh", "-c", "brew install " + tool.Brew)

Exceptions justifiées :

  • Le script Homebrew officiel (/bin/bash -c "$(curl -fsSL <URL>)") — URL hardcodée
  • Le clone p10k (git clone <URL hardcodée>) — pas d'interpolation d'input user

6. Pas de path traversal

Les paths dir: du catalogue ne sont jamais utilisés pour écrire — uniquement pour vérifier l'existence (os.Stat). Aucun os.Open(userControlled) qui pourrait suivre ../../../etc/passwd.

7. Tests sur paths critiques

Couverture minimum sur les fonctions sécurité-critiques :

Fonction Tests Couverture
atomicReplace 5 cas (fresh, backup, perms, stale .bak, tmp cleanup) 100 %
healthCheck 5 cas (happy, mismatch, crash, non-exec, missing) 100 %
parseSHA256SUMS 5 cas (standard, binary-mode, comments, empty, case folding) 100 %
validateCatalog + validateProfiles 9 cas de rejet 100 %
IsInstalledCtx cancellation respect + edge cases partial
Install worker pool 6 cas (concurrency, cancellation, empty, present, mid-loop cancel) partial

📦 Gestion des dépendances

Pinning

Niveau Mécanisme
Go runtime go 1.26.x dans go.mod + CI
Deps Go directes Versions exactes dans go.mod (require ... vX.Y.Z)
Hashes de deps go.sumgo mod verify rejette toute manipulation
GitHub Actions Pinning par SHA commit (jamais par tag mutable). Cf. .github/workflows/*.yml.
Releases en dépendance gh attestation verify permet de valider l'origine d'une release officielle

Audit régulier

À mettre en CI (roadmap V1.1) :

# Vulnérabilités connues dans les deps Go
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...

# Audit statique de sécurité (optionnel, plus bruyant)
brew install gosec
gosec ./...

Dependabot

À activer (roadmap V1.1) : .github/dependabot.yml qui crée des PRs automatiques pour les bumps de deps Go + GitHub Actions, avec auto-merge si CI verte sur les patches.

Pas de deps GUI ou réseau exotiques

Les seules deps significatives sont :

  • github.com/charmbracelet/bubbletea, bubbles, lipgloss (Charm, TUI)
  • github.com/spf13/cobra, pflag (Cobra, CLI)
  • github.com/goccy/go-yaml (YAML)

Toutes maintenues, populaires, auditables.


🤖 Sécurité CI/CD

Branch protection sur main

✓ Require pull request before merging
✓ Required status check : "Lint + Test + Build"
✓ Require branches to be up to date
✓ Require linear history
✓ Block force pushes
✓ Block deletions
✓ Require conversation resolution
✓ enforce_admins : true   (le mainteneur lui-même ne peut pas contourner)

Conséquence : aucun code ne peut atteindre main sans avoir passé la CI complète (lint, vet, test -race, build, go mod tidy check).

Permissions GitHub Actions minimales

Workflow Permissions globales Permissions job
ci.yml contents: read (aucune surcharge)
release.yml contents: read Job release : contents: write + id-token: write + attestations: write uniquement

Principe du moindre privilège strict. Pas de permissions: write-all.

Actions tierces pinnées par SHA

uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11    # v4.1.1
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32     # v5.0.0
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20  # v9.2.0
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32  # v4.1.0
uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564  # v2.0.4

Un attaquant qui repush un tag (actions/checkout@v4) ne peut pas affecter le projet : les SHA sont des hashes git immuables.

Secrets

Aucun secret de production dans le repo ou la CI :

  • L'attestation OIDC GitHub utilise un token éphémère généré par le runtime de l'action, pas de clé privée stockée
  • Pas de credentials Apple Developer (signature pas implémentée)
  • Pas de token d'API tiers

Les seuls secrets utilisés en CI sont les tokens auto-générés par GitHub (GITHUB_TOKEN), avec scope minimum.

Pas de pull_request_target

Ce trigger GitHub Actions est dangereux car il run avec les permissions du repo cible et accès aux secrets. Jamais utilisé dans ce projet — tous nos workflows utilisent pull_request standard.


👤 Pour les utilisateurs

Setup minimum sécurisé

# 1. Install via URL canonique (jamais via mirror)
curl -fsSL https://raw.githubusercontent.com/yanix2445/setup-macos/main/install.sh | bash

# 2. Vérifier l'attestation au moins une fois
gh attestation verify ~/.local/bin/setup-macos --owner yanix2445

# 3. Garder à jour
setup-macos update

Audit avant d'exécuter (parano mode)

Pour les environnements sensibles (entreprise, prod, machines de signature de release) :

# 1. Inspecter install.sh AVANT d'exécuter
curl -fsSL https://raw.githubusercontent.com/yanix2445/setup-macos/main/install.sh -o install.sh
less install.sh          # lecture humaine
bash install.sh          # exécution explicite

# 2. Vérifier le hash et l'attestation
gh attestation verify ~/.local/bin/setup-macos --owner yanix2445
shasum -a 256 ~/.local/bin/setup-macos

# 3. Vérifier qu'aucune entrée suspecte n'a été ajoutée
grep "setup-macos\|brew shellenv\|.local/bin" ~/.zprofile ~/.zshrc

# 4. (Optionnel) lancer dans un user dédié ou une VM

Audit du code source

git clone https://github.com/yanix2445/setup-macos
cd setup-macos

# Tests passent ?
go test -race ./...

# Lint propre ?
golangci-lint run

# Pas de vulns connues dans les deps ?
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...

# Build reproductible ?
make release-build
shasum -a 256 bin/setup-macos-darwin-arm64    # doit matcher la release officielle

Désinstallation propre

setup-macos uninstall
# OU manuellement :
rm -f ~/.local/bin/setup-macos ~/.local/bin/setup-macos.bak
rm -rf ~/.local/share/setup-macos
# Optionnel : retirer les lignes ajoutées dans ~/.zprofile / ~/.zshrc

🚨 Réponse à incident

Runbook côté mainteneur

Une vulnérabilité confirmée déclenche cette séquence :

1. Triage     : valider la repro, scorer CVSS, identifier les versions affectées
2. Containment: si exploitation active observée → advisory immédiat
3. Fix        : branche security/CVE-YYYY-NNNNN, PR (review accélérée, 1 reviewer suffit)
4. Test       : -race + scénario d'exploitation reproduit puis confirmé fixé
5. Release    : bump patch (X.Y.Z+1), tag, CI auto-build + sign
6. Advisory   : publier l'advisory GitHub avec détails techniques + workaround
7. Notif      : mention dans CHANGELOG.md sous section "Sécurité"
8. CVE        : attribué automatiquement via GitHub
9. Backport   : si la branche n-1 est encore en maintenance, rétroporter
10. Post-mort : ajouter test de régression, ajouter détection au modèle de menace

Runbook côté utilisateur

Une vulnérabilité divulguée déclenche :

1. Lire l'advisory GitHub pour identifier :
   - les versions affectées
   - les conditions d'exploitation
   - le workaround temporaire (si patch pas dispo)
2. Vérifier ta version :
   setup-macos --version
3. Si vulnérable :
   setup-macos update                              # vers la version patchée
   gh attestation verify ~/.local/bin/setup-macos --owner yanix2445
4. Confirmer la nouvelle version :
   setup-macos --version    # doit être ≥ version patchée

Workaround si pas de patch immédiat

Type de vuln Workaround
RCE via install.sh SKIP_VERIFY=0 est le défaut — ne pas le contourner
Exploit via catalog.yaml Utiliser uniquement catalog.yaml officiel (ne pas appliquer un YAML d'origine inconnue)
Exploit via env var Désactiver les env vars suspectes : unset SKIP_VERIFY INSTALL_DIR
RCE via subprocess brew Désinstaller temporairement : setup-macos uninstall

🗺️ Roadmap sécurité

Suivi des améliorations sécurité planifiées :

V1.1 (court terme)

  • govulncheck en CI — détection automatique de vulnérabilités connues dans les deps Go
  • Dependabot activé pour Go modules + GitHub Actions
  • SBOM (Software Bill of Materials) au format CycloneDX dans chaque release
  • Vérification automatique de l'attestation dans install.sh et setup-macos update (bundle de cosign light)
  • CodeQL scanning sur les PRs

V1.x (moyen terme)

  • Apple Developer ID signature + notarisation (élimine warning Gatekeeper sur download manuel)
  • gosec statique en CI (fail soft)
  • Fuzzing régulier sur parseurs (YAML loader, SHA256SUMS parser) via go test -fuzz en nightly
  • SECURITY.md traduit en anglais pour reach international

V2.x (long terme)

  • Reproductible builds vérifiés en CI — second runner indépendant qui rebuild et compare le hash
  • Multi-signer attestation (au moins 2 mainteneurs signent les releases)
  • Threat modeling formal review annuel par un tiers

📜 Conformité standards

Standard Niveau Note
SLSA Build Level L3 Provenance signée, build hosted, transparency log
NIST SSDF PO + PS (partiel) Pratiques préparation org + protection software ; règles produit (PW) partielles
OpenSSF Best Practices Pas encore certifié Roadmap : passer le badge Silver
Conventional Commits Conforme Traçabilité historique
Keep a Changelog Conforme Section Sécurité distincte
SemVer 2.0 Strict Politique de support par branche

📖 Glossaire

Terme Définition
Attestation Document signé qui certifie comment et où un artefact a été construit. Format standard : in-toto.
CVE Common Vulnerabilities and Exposures — identifiant unique d'une vulnérabilité publique (ex : CVE-2024-12345).
CVSS Common Vulnerability Scoring System — score de 0 à 10 de la criticité d'une vuln. ≥ 9.0 = critique.
MITM Man-in-the-Middle — attaquant qui s'interpose entre client et serveur.
OIDC OpenID Connect — protocole d'authentification. GitHub Actions émet un token OIDC qui permet de signer sans clé privée.
PoC Proof of Concept — preuve d'exploitabilité d'une vuln.
RCE Remote Code Execution — exécution de code arbitraire à distance. Le plus critique.
Rekor Transparency log public de Sigstore — toute signature y est enregistrée immuablement.
SBOM Software Bill of Materials — inventaire des composants d'un logiciel (format CycloneDX, SPDX).
SHA256SUMS Fichier texte qui liste les hashes SHA-256 attendus de plusieurs fichiers, format <hash> <filename>.
Sigstore Écosystème open-source pour signer sans clé privée via OIDC (cosign, Fulcio CA, Rekor log).
SLSA Supply chain Levels for Software Artifacts — standard de provenance/sécurité, niveaux 1-4.
TOCTOU Time of check to time of use — race condition entre vérification et utilisation d'une ressource.
Transparency log Log append-only public et signé, où toute action est traçable et non-réfutable.

🔗 Références

Standards & guides

Outils mentionnés

Documentation projet


Dernière mise à jour : v1.2.0 — toute modification de ce document est tracée via git history.

There aren't any published security advisories