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é.
- TL;DR
- Versions supportées
- Signaler une vulnérabilité
- Politique de divulgation coordonnée
- Modèle de menace
- Architecture de sécurité
- Pratiques de développement sécurisé (Go)
- Gestion des dépendances
- Sécurité CI/CD
- Pour les utilisateurs
- Réponse à incident
- Roadmap sécurité
- Conformité standards
- Glossaire
- Références
- 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
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 updatePolitique 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.
N'ouvre JAMAIS d'issue publique pour une vulnérabilité. Cela exposerait des utilisateurs avant qu'un correctif soit disponible.
- GitHub Security Advisory privé ⭐ recommandé
- https://github.com/yanix2445/setup-macos/security/advisories/new
- Avantage : workflow intégré (CVE auto, advisory public au moment du fix, crédit du reporter)
- Email :
yanis@yanixlabs.com- Sujet préfixé
[security] setup-macos: ... - Réponse sous 72 h ouvrées
- Sujet préfixé
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 |
- 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)
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
- 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+90maximum, le temps que les usagers majeurs puissent mettre à jour.
- 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.
- 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é
┌─────────────────────────────────────────────────────────────────┐
│ 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è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).
| 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) |
| # | 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é | Aucune — grep -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. |
| 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). |
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 |
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 jsonL'output JSON contient :
subject.name: nom du binaire attestépredicate.buildDefinition.externalParameters.workflow.repository: repo sourcepredicate.runDetails.builder.id: identité du runner (https://github.com/actions/runner)
# 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-macosEscape 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é")
}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-macosDrapeaux 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-arm64Les deux hashes doivent être strictement égaux. Sinon, il y a soit un environnement de build différent, soit un acte malveillant.
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 .bak → os.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 |
Aligné sur les Secure Coding Guidelines de Go et OWASP Go Secure Coding.
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")
}- Aucun
panic()en code de production (cherche :grep -r "panic(" cmd/ internal/→ vide hors tests) - Aucun
log.Fatal()(idem) - Tout
errorest propagé avecfmt.Errorf("contexte : %w", err)pour préserver la chaîneerrors.Is/errors.As - Les rares
_ =sont justifiés en commentaire ou concernent desdefer Close()où l'erreur n'apporte rien
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) errorSubprocess : toujours exec.CommandContext(ctx, ...), jamais exec.Command(...). Permet à un Ctrl+C utilisateur de tuer proprement les processus enfants.
Patterns appliqués dans internal/brew/install.go (worker pool) :
- Sémaphore borné (
chan struct{}) au lieu de fork sans limite defer wg.Wait()AVANTdefer close(channel)(LIFO) — évitepanic: send on closed channelselect { 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
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
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.
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 |
| 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.sum — go 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 |
À 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 ./...À 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.
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.
✓ 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).
| 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.
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.4Un attaquant qui repush un tag (actions/checkout@v4) ne peut pas affecter le projet : les SHA sont des hashes git immuables.
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.
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.
# 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 updatePour 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 VMgit 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 officiellesetup-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 / ~/.zshrcUne 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
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
| 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 |
Suivi des améliorations sécurité planifiées :
-
govulnchecken 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.shetsetup-macos update(bundle de cosign light) - CodeQL scanning sur les PRs
- Apple Developer ID signature + notarisation (élimine warning Gatekeeper sur download manuel)
-
gosecstatique en CI (fail soft) - Fuzzing régulier sur parseurs (YAML loader, SHA256SUMS parser) via
go test -fuzzen nightly - SECURITY.md traduit en anglais pour reach international
- 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
| 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 |
| 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. |
- Go Security Policy
- Go Secure Coding Guidelines (OWASP)
- SLSA v1.0 Specification
- GitHub Artifact Attestations
- Sigstore documentation
- NIST SSDF (SP 800-218)
- OpenSSF Scorecard — auto-évaluation OSS
- govulncheck — scanner de vulns Go
- gosec — analyse statique sécurité Go
- cosign — signature keyless
- Dependabot — bumps de deps automatiques
- CONTRIBUTING.md — règles d'écriture de code, tests, commits
- CHANGELOG.md — historique avec sections
Sécuritédédiées - .github/workflows/release.yml — pipeline de release
- .github/workflows/ci.yml — pipeline CI
Dernière mise à jour : v1.2.0 — toute modification de ce document est tracée via git history.