7 changed files with 222 additions and 233 deletions

No files matched your search

+5 -30
View File
@@ -245,36 +245,11 @@ destinée au poste **WAPT Console uniquement**, pas au paquet agent. L’install
dans le répertoire de templates de la Console sous ce nom exact, puis choisir dans le répertoire de templates de la Console sous ce nom exact, puis choisir
la clé d’audit `hardeningkitty / hardeningkitty`. Elle exploite le helper la clé d’audit `hardeningkitty / hardeningkitty`. Elle exploite le helper
Mustache WAPT `Items` pour parcourir les dictionnaires de catégories et de Mustache WAPT `Items` pour parcourir les dictionnaires de catégories et de
contrôles. WAPT expose le document JSON sous `value`; les informations de contrôles. Les valeurs variables utilisent les tags échappés `{{...}}`; aucun
machine, comme `computer_fqdn`, restent à la racine du contexte Mustache. Le JavaScript ni triple-brace non échappé n’est utilisé. Le template est une vue
template suit cette structure et les collections sont parcourues avec de synthèse et d’analyse, pas une preuve de conformité indépendante. Sa syntaxe
`Items value.categories` et `Items value.controls`. a été contrôlée statiquement, mais son rendu dans une Console réelle doit être
validé avant diffusion.
Lors de l’installation du paquet sur Windows, `install()` copie automatiquement
le template avec les helpers WAPT vers
`makepath(programfiles32, "wapt", "templates")`, soit le répertoire standard
de templates de l’agent/console WAPT 32 bits. Le fichier porte le nom exact
`host_audit_hardeningkitty_hardeningkitty.html`.
Sur une console macOS/Linux dont le répertoire de templates est
`/opt/wapt/templates`, le paquet Windows ne peut pas effectuer cette copie.
Installer ou mettre à jour le fichier depuis la racine du paquet :
```sh
sudo install -m 0644 \
console-templates/host_audit_hardeningkitty_hardeningkitty.html \
/opt/wapt/templates/host_audit_hardeningkitty_hardeningkitty.html
```
Après copie, ouvrir le rapport d’audit et sélectionner la clé
`hardeningkitty / hardeningkitty`. Le template est une vue console; il ne
modifie ni la configuration Defender ni les données du rapport.
Les valeurs variables utilisent les tags Mustache échappés; aucun JavaScript
ni triple-brace non échappé n’est utilisé. Le template est une vue de synthèse
et d’analyse, pas une preuve de conformité indépendante. Son rendu a été testé
avec le moteur Mustache WAPT sur des données synthétiques, mais doit être
contrôlé dans la version réelle de WAPT Console avant diffusion.
Les anciennes clés fragmentées restent éventuellement visibles dans Les anciennes clés fragmentées restent éventuellement visibles dans
l’historique antérieur à cette version; elles ne sont plus émises par le code l’historique antérieur à cette version; elles ne sont plus émises par le code
@@ -1,163 +1,236 @@
<!-- <!-- Comitari / HardeningKitty - WAPT Console Mustache audit view.
Comitari - Audit de durcissement Windows / HardeningKitty Section=hardeningkitty; key=hardeningkitty.
WAPT: section=hardeningkitty, key=hardeningkitty Keep this file on WAPT CONSOLE machines, not on audited endpoints.
WAPT audit rendering context: audit JSON is under value; host metadata is at root. All dynamic values use HTML-escaped Mustache tags. No JavaScript. -->
No JavaScript, external stylesheets or external resources.
-->
<style> <style>
.comi-hk { color:#23364f; background:#fff; font-family:Arial,Helvetica,sans-serif; font-size:13px; line-height:1.48; max-width:100%; padding:22px 22px 26px; box-sizing:border-box; } .hk-report {
.comi-hk * { box-sizing:border-box; } box-sizing: border-box; background: #fff; color: #202b3b;
.comi-hk h1,.comi-hk h2,.comi-hk h3,.comi-hk p { margin:0; } font-family: "Segoe UI", Arial, sans-serif; font-size: 13px;
.comi-hk .eyebrow { color:#3d6490; font-size:10px; font-weight:700; letter-spacing:0.065em; text-transform:uppercase; } line-height: 1.45; padding: 20px; max-width: 1500px; margin: 0 auto;
.comi-hk h1 { color:#173354; font-size:23px; line-height:1.22; margin:3px 0 4px; } }
.comi-hk .sub { color:#5b708b; font-size:12px; } .hk-report *, .hk-report *:before, .hk-report *:after { box-sizing: border-box; }
.comi-hk h2 { color:#193656; font-size:16px; margin:0 0 12px; } .hk-report .hk-header { display:flex; align-items:center; justify-content:space-between; gap:14px; padding-bottom:18px; border-bottom:1px solid #e3e8ee; }
.comi-hk header { padding-bottom:16px; border-bottom:1px solid #e4ebf3; } .hk-report .hk-brand { font-size:11px; letter-spacing:2px; font-weight:800; color:#4c6b8b; text-transform:uppercase; }
.comi-hk .meta { color:#5c7088; padding:11px 0 15px; font-size:11px; } .hk-report h1 { font-size:23px; color:#132a45; margin:3px 0 2px; line-height:1.2; }
.comi-hk .meta span { margin-right:12px; display:inline-block; padding-bottom:3px; } .hk-report h2 { font-size:16px; color:#132a45; margin:24px 0 11px; }
.comi-hk .meta strong { color:#2d4667; } .hk-report p { margin:4px 0 8px; }
.comi-hk .section { margin-top:22px; } .hk-report .hk-muted { color:#65758a; font-size:12px; }
.comi-hk .cards { display:flex; flex-wrap:wrap; gap:10px; } .hk-report .hk-overall { display:inline-block; padding:6px 13px; border-radius:5px; font-size:12px; font-weight:800; letter-spacing:.3px; background:#edf2f7; color:#31465d; }
.comi-hk .card { flex:1 1 124px; min-width:108px; border:1px solid #e2eaf3; background:#f8fbfe; border-radius:8px; padding:12px 13px; } .hk-report .hk-overall-ERROR { background:#fde8e7; color:#a52a23; }
.comi-hk .card .label { font-size:11px; color:#637a94; line-height:1.3; } .hk-report .hk-overall-WARNING { background:#fff1db; color:#8d5400; }
.comi-hk .card .num { font-size:26px; font-weight:700; line-height:1.2; color:#193656; margin-top:5px; } .hk-report .hk-overall-OK { background:#dff5e9; color:#096b3f; }
.comi-hk .card.bad .num { color:#b63838; } .hk-report .hk-meta { margin:15px 0 18px; display:flex; flex-wrap:wrap; gap:8px 24px; color:#5d7188; font-size:12px; }
.comi-hk .card.good .num { color:#287c60; } .hk-report .hk-meta strong { color:#243c58; }
.comi-hk .card.medium .num { color:#b86a27; } .hk-report .hk-score-layout { display:flex; gap:15px; align-items:stretch; flex-wrap:wrap; }
.comi-hk .progress { height:10px; background:#e9eff6; border-radius:20px; overflow:hidden; margin-top:12px; } .hk-report .hk-score { background:#f4f7fb; border:1px solid #e5ebf1; border-radius:9px; flex:1 1 270px; padding:17px 18px; min-width:220px; }
.comi-hk .progress-fill { background:#2d8b75; height:10px; border-radius:20px; } .hk-report .hk-score-label { font-size:12px; color:#586a7c; margin:0; }
.comi-hk .progress-legend { display:flex; justify-content:space-between; gap:12px; color:#60738e; font-size:11px; margin-top:5px; } .hk-report .hk-score-number { font-size:38px; line-height:1.15; font-weight:750; color:#17395e; margin:4px 0 11px; }
.comi-hk .callout { background:#f2f6fc; border-left:3px solid #3c719d; border-radius:4px; padding:10px 12px; color:#435d78; font-size:12px; margin-top:12px; } .hk-report .hk-score-number span { font-size:19px; font-weight:500; color:#728197; }
.comi-hk .callout-warn { background:#fff8ed; border-left-color:#d18a30; color:#684e2c; } .hk-report .hk-track { height:9px; background:#d8e3ee; border-radius:20px; overflow:hidden; }
.comi-hk .table-wrap { max-width:100%; overflow-x:auto; border:1px solid #e3eaf2; border-radius:7px; } .hk-report .hk-fill { height:100%; background:#278e65; max-width:100%; }
.comi-hk table { border-collapse:collapse; width:100%; font-size:12px; } .hk-report .hk-score-foot { display:flex; justify-content:space-between; gap:12px; margin-top:9px; color:#66798b; font-size:11px; }
.comi-hk thead th { background:#f2f6fb; border-bottom:1px solid #dfe7f1; padding:9px 10px; text-align:left; font-size:11px; font-weight:700; color:#3d5473; } .hk-report .hk-kpis { flex:3 1 460px; display:grid; grid-template-columns:repeat(3,minmax(110px,1fr)); gap:10px; }
.comi-hk tbody td { border-bottom:1px solid #edf1f6; padding:9px 10px; vertical-align:top; } .hk-report .hk-kpi { border:1px solid #e5ebf1; border-radius:9px; background:#fff; padding:12px 14px; }
.comi-hk tbody tr:last-child td { border-bottom:0; } .hk-report .hk-kpi strong { display:block; font-size:25px; line-height:1.15; color:#203752; }
.comi-hk tbody tr:nth-child(even) { background:#fbfcfe; } .hk-report .hk-kpi span { display:block; margin-top:3px; font-size:11px; color:#687b90; }
.comi-hk .n { text-align:right; white-space:nowrap; } .hk-report .hk-kpi.hk-high strong { color:#c23b34; }
.comi-hk .name { font-weight:600; color:#203a5a; } .hk-report .hk-kpi.hk-medium strong { color:#b77910; }
.comi-hk .muted { color:#75869a; font-size:11px; margin-top:4px; overflow-wrap:anywhere; } .hk-report .hk-kpi.hk-low strong { color:#9d8a22; }
.comi-hk .small { color:#5b708a; font-size:11px; margin-top:4px; overflow-wrap:anywhere; } .hk-report .hk-kpi.hk-passed strong { color:#178256; }
.comi-hk .id { font-family:Consolas,"Courier New",monospace; color:#60718b; font-size:11px; white-space:nowrap; } .hk-report .hk-banner { padding:12px 15px; border:1px solid #f3d9a2; background:#fff9eb; color:#74531f; border-radius:7px; margin:16px 0; }
.comi-hk .pill { display:inline-block; padding:3px 7px; font-size:11px; font-weight:700; border-radius:99px; background:#edf2f7; color:#49617d; white-space:nowrap; } .hk-report .hk-banner-error { border-color:#f0bebc; background:#fff1f0; color:#882b26; }
.comi-hk .pill.severity-high { background:#fde8e8; color:#aa2424; } .hk-report .hk-section { border:1px solid #e3e9f0; border-radius:8px; overflow:hidden; margin:14px 0; }
.comi-hk .pill.severity-medium { background:#fff1df; color:#985c20; } .hk-report .hk-section > summary { cursor:pointer; padding:12px 15px; background:#f7f9fc; color:#243e58; font-size:14px; font-weight:700; }
.comi-hk .pill.severity-low { background:#eaf2ff; color:#3b6ca9; } .hk-report .hk-section > summary:hover { background:#eff5fc; }
.comi-hk .pill.status-failed { background:#fee9e8; color:#b12f2a; } .hk-report .hk-section-content { padding:4px 13px 14px; }
.comi-hk .pill.status-passed { background:#e0f5ec; color:#207956; } .hk-report .hk-scroll { overflow-x:auto; max-width:100%; }
.comi-hk .pill.status-ignored,.comi-hk .pill.status-skipped,.comi-hk .pill.status-not_applicable { background:#eff2f5; color:#687988; } .hk-report .hk-table { width:100%; border-collapse:collapse; border-spacing:0; min-width:690px; text-align:left; }
.comi-hk .note { color:#657c93; font-size:11px; margin:10px 0; } .hk-report .hk-table th { padding:9px 9px; color:#62758b; background:#f5f8fb; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.35px; border-bottom:1px solid #dfe7ef; }
.comi-hk footer { color:#647b96; font-size:11px; margin-top:24px; border-top:1px solid #e5ebf2; padding-top:12px; } .hk-report .hk-table td { padding:10px 9px; vertical-align:top; border-bottom:1px solid #edf0f4; overflow-wrap:anywhere; }
.comi-hk .mono { font-family:Consolas,"Courier New",monospace; overflow-wrap:anywhere; } .hk-report .hk-table tbody tr:hover { background:#f7fafe; }
.comi-hk .notfound { border:1px solid #e9d09e; background:#fff9ef; border-radius:6px; padding:16px; margin-top:20px; color:#805822; } .hk-report .hk-table tbody tr:last-child td { border-bottom:0; }
.hk-report .hk-table .hk-id { white-space:nowrap; font-family:Consolas,monospace; color:#54708a; }
.hk-report .hk-table .hk-control-title { font-weight:600; color:#223b54; }
.hk-report .hk-badge { display:inline-block; white-space:nowrap; border-radius:5px; padding:2px 7px; font-size:11px; font-weight:700; background:#edf2f7; color:#54677c; }
.hk-report .hk-sev-high { background:#fce6e6; color:#a52b28; }
.hk-report .hk-sev-medium { background:#fff0d4; color:#9d5e03; }
.hk-report .hk-sev-low { background:#fff9db; color:#947d17; }
.hk-report .hk-sev-unknown { background:#ebeff4; color:#58677c; }
.hk-report .hk-state-passed { color:#118159; font-weight:650; }
.hk-report .hk-state-failed { color:#b04335; font-weight:650; }
.hk-report .hk-state-skipped, .hk-report .hk-state-unknown, .hk-report .hk-state-ignored { color:#8c5810; font-weight:650; }
.hk-report .hk-value { font-family:Consolas,"Courier New",monospace; font-size:11px; color:#344c66; word-break:break-word; }
.hk-report .hk-small { color:#64748b; font-size:11px; }
.hk-report .hk-detail { margin:5px 0 0; }
.hk-report .hk-detail summary { cursor:pointer; display:inline; color:#245b94; font-weight:600; }
.hk-report .hk-detail-content { margin:8px 0 4px; padding:8px 10px; background:#f6f9fc; border-left:3px solid #b7ccde; color:#465c74; font-size:11px; }
.hk-report .hk-detail-content p { margin:4px 0; }
.hk-report .hk-filters { padding:12px 0 8px; }
.hk-report .hk-filters input[type=radio] { position:absolute; opacity:0; height:1px; width:1px; }
.hk-report .hk-filters label { display:inline-block; margin:0 5px 8px 0; padding:5px 12px; border-radius:6px; border:1px solid #dbe4ed; cursor:pointer; color:#556e85; font-weight:600; font-size:12px; }
.hk-report .hk-filters label:hover { background:#f1f5f9; }
.hk-report #hk-filter-all:checked + label,
.hk-report #hk-filter-issues:checked + label,
.hk-report #hk-filter-high:checked + label,
.hk-report #hk-filter-passed:checked + label { background:#275d93; color:white; border-color:#275d93; }
.hk-report #hk-filter-issues:checked ~ .hk-scroll .hk-row-passed,
.hk-report #hk-filter-issues:checked ~ .hk-scroll .hk-row-excluded,
.hk-report #hk-filter-issues:checked ~ .hk-scroll .hk-row-not_applicable { display:none; }
.hk-report #hk-filter-high:checked ~ .hk-scroll .hk-row:not(.hk-row-failed),
.hk-report #hk-filter-high:checked ~ .hk-scroll .hk-row:not(.hk-risk-high) { display:none; }
.hk-report #hk-filter-passed:checked ~ .hk-scroll .hk-row:not(.hk-row-passed) { display:none; }
.hk-report .hk-note { border-left:3px solid #b9c9db; padding:8px 10px; margin:14px 0; font-size:12px; color:#5b6f84; background:#f6f9fc; }
.hk-report .hk-footer { padding-top:11px; margin-top:22px; border-top:1px solid #e6eaf0; color:#73859a; font-size:11px; }
.hk-report .hk-no-data { margin:18px 0; padding:15px; border:1px solid #e8dfba; border-radius:6px; background:#fffaf0; }
@media (max-width:750px) {
.hk-report { padding:10px; }
.hk-report .hk-kpis { grid-template-columns:repeat(2,minmax(110px,1fr)); }
.hk-report h1 { font-size:18px; }
}
</style> </style>
<div class="comi-hk"> <div class="hk-report">
<header> <div class="hk-header">
<p class="eyebrow">COMITARI / HARDENINGKITTY</p> <div>
<div class="hk-brand">COMITARI / HARDENINGKITTY</div>
<h1>Audit de durcissement Windows</h1> <h1>Audit de durcissement Windows</h1>
<p class="sub">Analyse des écarts par rapport au référentiel de sécurité</p> <div class="hk-muted">Analyse des &eacute;carts par rapport au r&eacute;f&eacute;rentiel de s&eacute;curit&eacute;</div>
</header> </div>
<span class="hk-overall hk-overall-{{status}}">{{status}}</span>
{{#value.summary}}
<div class="meta">
<span><strong>Poste :</strong> {{computer_fqdn}}</span>
<span><strong>Système :</strong> {{value.host.os_caption}} {{value.host.display_version}} (build {{value.host.build}})</span>
<span><strong>Exécuté le :</strong> {{value.scan.date_utc}}</span>
<span><strong>Source :</strong> {{value.scan.source}}</span>
<span><strong>Statut :</strong> {{value.status}}</span>
</div> </div>
<section class="section"> {{#error}}
<h2>Vue d'ensemble</h2> <div class="hk-banner hk-banner-error">
<div class="cards"> <strong>Audit incomplet ou indisponible.</strong>
<div class="card"><div class="label">Contrôles vérifiés</div><div class="num">{{checked}}</div></div> <p>Code : {{error.code}} — type : {{error.type}}</p>
<div class="card good"><div class="label">Conformes</div><div class="num">{{passed}}</div></div> <p>{{error.description}}</p>
<div class="card bad"><div class="label">Non conformes</div><div class="num">{{failed}}</div></div> <p>V&eacute;rifier les journaux de l'agent WAPT sur le poste concern&eacute;.</p>
<div class="card"><div class="label">Conformité</div><div class="num">{{compliant_percent}} %</div></div>
<div class="card bad"><div class="label">Criticité élevée</div><div class="num">{{high}}</div></div>
<div class="card medium"><div class="label">Criticité moyenne</div><div class="num">{{medium}}</div></div>
<div class="card"><div class="label">Criticité faible</div><div class="num">{{low}}</div></div>
</div> </div>
<div class="progress"><div class="progress-fill" style="width:{{compliant_percent}}%;"></div></div> {{/error}}
<div class="progress-legend"><span>Score de conformité observé</span><span>{{passed}} / {{checked}} contrôles conformes</span></div>
<div class="callout callout-warn">Ce rapport est informatif : aucune correction automatique n'a été appliquée. Les écarts sont évalués par rapport au profil sélectionné, pas nécessairement contre une configuration adaptée à tous les environnements.</div>
</section>
{{/value.summary}}
{{#value.error}} {{#summary}}
<div class="notfound"><strong>Audit en erreur : {{code}}</strong><br>{{description}}<span class="small">Type technique : {{type}}</span></div> <div class="hk-meta">
{{/value.error}} <span><strong>Machine :</strong> {{host.os_caption}} {{host.display_version}} (build {{host.build}})</span>
<span><strong>R&eacute;f&eacute;rentiel :</strong> {{benchmark.name}}</span>
<span><strong>Source :</strong> {{scan.source}}</span>
<span><strong>Audit UTC :</strong> {{scan.date_utc}}</span>
</div>
<div class="hk-score-layout">
<div class="hk-score">
<p class="hk-score-label">Taux de conformit&eacute;</p>
<div class="hk-score-number">{{compliant_percent}} <span>%</span></div>
<div class="hk-track"><div class="hk-fill" style="width:{{compliant_percent}}%;"></div></div>
<div class="hk-score-foot"><span>{{passed}} conformes</span><span>{{expected}} attendus</span></div>
</div>
<div class="hk-kpis">
<div class="hk-kpi hk-high"><strong>{{high}}</strong><span>&Eacute;carts &eacute;lev&eacute;s</span></div>
<div class="hk-kpi hk-medium"><strong>{{medium}}</strong><span>&Eacute;carts moyens</span></div>
<div class="hk-kpi hk-low"><strong>{{low}}</strong><span>&Eacute;carts faibles</span></div>
<div class="hk-kpi hk-passed"><strong>{{passed}}</strong><span>Conformes</span></div>
<div class="hk-kpi"><strong>{{unknown}}</strong><span>Inconnus</span></div>
<div class="hk-kpi"><strong>{{skipped}}</strong><span>Non ex&eacute;cut&eacute;s</span></div>
</div>
</div>
{{/summary}}
{{^value.summary}} {{#summary}}
{{^value.error}} {{#privacy.current_values_published}}
<div class="notfound"><strong>Données d'audit absentes.</strong> La valeur reçue ne contient ni synthèse ni erreur structurée.</div> <p class="hk-note">Valeurs constat&eacute;es : publication activ&eacute;e. V&eacute;rifier les droits d'acc&egrave;s aux donn&eacute;es d'audit.</p>
{{/value.error}} {{/privacy.current_values_published}}
{{/value.summary}} {{^privacy.current_values_published}}
<p class="hk-note">Les valeurs effectivement lues sur le poste ne sont pas publi&eacute;es par d&eacute;faut. Le CSV d&eacute;taill&eacute; reste disponible localement sur le poste audit&eacute;.</p>
{{/privacy.current_values_published}}
{{#value.categories}} <h2>&Eacute;carts &agrave; examiner en priorit&eacute;</h2>
<section class="section"> <p class="hk-muted">{{priority_total}} r&eacute;sultats non conformes ou non &eacute;valu&eacute;s. Aper&ccedil;u limit&eacute; &agrave; 25 contr&ocirc;les, class&eacute;s par gravit&eacute; puis cat&eacute;gorie (pas par risque exploitabilit&eacute;).</p>
<h2>Répartition par domaine</h2> <div class="hk-section">
<div class="table-wrap"> <div class="hk-scroll">
<table> <table class="hk-table">
<thead><tr><th>Domaine</th><th class="n">Contrôles</th><th class="n">Conformes</th><th class="n">Élevée</th><th class="n">Moyenne</th><th class="n">Faible</th><th class="n">Conformité</th></tr></thead> <thead><tr><th>ID</th><th>Cat&eacute;gorie</th><th>Gravit&eacute;</th><th>&Eacute;tat</th></tr></thead>
<tbody> <tbody>
{{#Items value.categories}} {{#priority_findings}}
<tr> <tr>
<td class="name">{{key}}</td> <td class="hk-id">{{id}}</td>
<td class="n">{{value.expected}}</td> <td>{{category}}</td>
<td class="n">{{value.passed}}</td> <td><span class="hk-badge hk-sev-{{severity}}">{{severity}}</span></td>
<td class="n">{{value.high}}</td> <td><span class="hk-state-{{status}}">{{status}}</span></td>
<td class="n">{{value.medium}}</td> </tr>
<td class="n">{{value.low}}</td> {{/priority_findings}}
<td class="n">{{value.compliant_percent}} %</td> {{^priority_findings}}
<tr><td colspan="4" class="hk-muted">Aucun &eacute;cart prioritaire.</td></tr>
{{/priority_findings}}
</tbody>
</table>
</div>
</div>
<details class="hk-section" open>
<summary>R&eacute;partition par cat&eacute;gorie</summary>
<div class="hk-section-content hk-scroll">
<table class="hk-table">
<thead><tr><th>Cat&eacute;gorie</th><th>Contr&ocirc;les</th><th>Conformes</th><th>Haut</th><th>Moyen</th><th>Faible</th><th>Non &eacute;valu&eacute;s</th><th>Conformit&eacute;</th></tr></thead>
<tbody>
{{#Items categories}}
<tr>
<td class="hk-control-title">{{key}}</td>
<td>{{value.expected}}</td>
<td>{{value.passed}}</td>
<td>{{value.high}}</td>
<td>{{value.medium}}</td>
<td>{{value.low}}</td>
<td>{{value.unknown}}</td>
<td><strong>{{value.compliant_percent}} %</strong></td>
</tr> </tr>
{{/Items}} {{/Items}}
</tbody> </tbody>
</table> </table>
</div> </div>
</section> </details>
{{/value.categories}}
{{#value.controls}} <details class="hk-section">
<section class="section"> <summary>Tous les contr&ocirc;les du benchmark ({{summary.expected}})</summary>
<h2>Détail des contrôles ({{ Count value.controls }})</h2> <div class="hk-section-content">
<p class="note">Les contrôles sont classés par identifiant HardeningKitty. Les valeurs observées ne sont affichées que lorsque leur publication est activée dans audit_config.json.</p> <p class="hk-muted">S&eacute;lectionner un filtre. Les d&eacute;tails de chaque contr&ocirc;le contiennent la justification et la m&eacute;thode de v&eacute;rification.</p>
<div class="table-wrap"> <div class="hk-filters">
<table> <input type="radio" id="hk-filter-all" name="hk-filter" checked><label for="hk-filter-all">Tous</label>
<thead><tr><th>ID</th><th style="min-width:260px">Contrôle et diagnostic</th><th>Criticité</th><th>État</th><th>Valeur cible</th>{{#value.privacy.current_values_published}}<th>Valeur observée</th>{{/value.privacy.current_values_published}}</tr></thead> <input type="radio" id="hk-filter-issues" name="hk-filter"><label for="hk-filter-issues">&Eacute;carts / Inconnus</label>
<input type="radio" id="hk-filter-high" name="hk-filter"><label for="hk-filter-high">&Eacute;lev&eacute;s uniquement</label>
<input type="radio" id="hk-filter-passed" name="hk-filter"><label for="hk-filter-passed">Conformes</label>
<div class="hk-scroll">
<table class="hk-table">
<thead><tr><th>ID</th><th>Contr&ocirc;le et analyse</th><th>Cat&eacute;gorie</th><th>Gravit&eacute;</th><th>&Eacute;tat</th><th>Valeur cible</th>{{#privacy.current_values_published}}<th>Valeur observ&eacute;e</th>{{/privacy.current_values_published}}</tr></thead>
<tbody> <tbody>
{{#Items value.controls}} {{#Items controls}}
<tr> <tr class="hk-row hk-row-{{value.status}} hk-risk-{{value.severity}}">
<td class="id">{{value.id}}</td> <td class="hk-id">{{key}}</td>
<td> <td>
<div class="name">{{value.name}}</div> <div class="hk-control-title">{{value.name}}</div>
<div class="muted">{{value.category}} &bull; {{value.method}}</div> <details class="hk-detail">
{{#value.explanation}}<div class="small">{{value.explanation}}</div>{{/value.explanation}} <summary>Voir l'analyse</summary>
{{#value.registry_path}}<div class="muted">Registre : <span class="mono">{{value.registry_path}} {{value.registry_item}}</span></div>{{/value.registry_path}} <div class="hk-detail-content">
{{#value.method_argument}}<div class="muted">Paramètre : <span class="mono">{{value.method_argument}}</span></div>{{/value.method_argument}} <p>{{value.explanation}}</p>
{{#value.reason}}<p><strong>Justification :</strong> {{value.reason}}</p>{{/value.reason}}
{{#value.method}}<p><strong>M&eacute;thode :</strong> {{value.method}}</p>{{/value.method}}
{{#value.method_argument}}<p><strong>Argument :</strong> <span class="hk-value">{{value.method_argument}}</span></p>{{/value.method_argument}}
{{#value.registry_path}}<p><strong>Registre :</strong> <span class="hk-value">{{value.registry_path}}</span></p>{{/value.registry_path}}
{{#value.registry_item}}<p><strong>Valeur registre :</strong> <span class="hk-value">{{value.registry_item}}</span></p>{{/value.registry_item}}
{{#value.operator}}<p><strong>Comparaison :</strong> {{value.operator}}</p>{{/value.operator}}
</div>
</details>
</td> </td>
<td><span class="pill severity-{{value.severity}}">{{value.severity_label}}</span></td> <td>{{value.category}}</td>
<td><span class="pill status-{{value.status}}">{{value.status_label}}</span></td> <td><span class="hk-badge hk-sev-{{value.severity}}">{{value.severity_label}}{{^value.severity_label}}{{value.severity}}{{/value.severity_label}}</span></td>
<td class="mono">{{value.recommended}}</td> <td><span class="hk-state-{{value.status}}">{{value.status_label}}{{^value.status_label}}{{value.status}}{{/value.status_label}}</span></td>
{{#value.privacy.current_values_published}}<td class="mono">{{value.current}}</td>{{/value.privacy.current_values_published}} <td class="hk-value">{{value.recommended}}</td>
{{#privacy.current_values_published}}<td class="hk-value">{{value.current}}</td>{{/privacy.current_values_published}}
</tr> </tr>
{{/Items}} {{/Items}}
</tbody> </tbody>
</table> </table>
</div> </div>
</section> </div>
{{/value.controls}} </div>
</details>
{{/summary}}
{{#value.summary}} <div class="hk-footer">HardeningKitty / Comitari &middot; Synth&egrave;se informative uniquement, aucune correction automatique &middot; R&eacute;f&eacute;rentiel : {{benchmark.name}}</div>
{{^value.controls}}
<p class="notfound">Aucun contrôle HardeningKitty disponible dans le contexte de rendu.</p>
{{/value.controls}}
{{/value.summary}}
<footer>
HardeningKitty / Comitari &middot; Synthèse informative uniquement, aucune correction automatique
&middot; Référentiel : <strong>{{value.benchmark.name}}</strong>
&middot; Profil : <strong>{{value.scan.profile}}</strong>
</footer>
</div> </div>
+1 -2
View File
@@ -2,9 +2,8 @@
"files": { "files": {
"WAPT/control": "4c3eef3800f9994b90cefb06ec35e019ba0c8fb8ffda8a216c7b6ca9eba457d4", "WAPT/control": "4c3eef3800f9994b90cefb06ec35e019ba0c8fb8ffda8a216c7b6ca9eba457d4",
"audit_config.json": "9fc18f556fd491e8e00e3a8b1efd864ad8036682e293a02c1f81f3411304a69b", "audit_config.json": "9fc18f556fd491e8e00e3a8b1efd864ad8036682e293a02c1f81f3411304a69b",
"console-templates/host_audit_hardeningkitty_hardeningkitty.html": "50d39d6414ee620d05b71539754b8ff7ecb4fab06fb5c3467798478107679df1",
"runner.ps1": "5e9787f5cc19d0fc4c0ede01a63188ed71de6ef49df596fbce7b2603093231cd", "runner.ps1": "5e9787f5cc19d0fc4c0ede01a63188ed71de6ef49df596fbce7b2603093231cd",
"setup.py": "d0b4ee0c444d1d2c0c698cc87047b4764d58a623ec647dfcf4c6d186f55b4d26", "setup.py": "0f4be0d4f2c42ace380dd6305a210c5a7d595508dbc566f652d86f3c7d874d43",
"vendor/HardeningKitty.psd1": "94378764787cd0c7125c5c3ce928803b46ee7d7d3fe21c2b27ddeb23c11377a7", "vendor/HardeningKitty.psd1": "94378764787cd0c7125c5c3ce928803b46ee7d7d3fe21c2b27ddeb23c11377a7",
"vendor/HardeningKitty.psm1": "b799ec1b17de5ce63f7a8ea34af3beba1d24fcaddf7e3774f797096f5c43e2a0", "vendor/HardeningKitty.psm1": "b799ec1b17de5ce63f7a8ea34af3beba1d24fcaddf7e3774f797096f5c43e2a0",
"vendor/LICENSE": "a879ba6ccdcd2ea55da97b999edd2c401c8589ca946f238236bf93aa40e74d56", "vendor/LICENSE": "a879ba6ccdcd2ea55da97b999edd2c401c8589ca946f238236bf93aa40e74d56",
-26
View File
@@ -55,8 +55,6 @@ REQUIRED_VENDOR_FILES = (
# A staged/installed directory stores the vendor files at its root (NOT /vendor). # A staged/installed directory stores the vendor files at its root (NOT /vendor).
RUNTIME_FILES = ('runner.ps1', 'audit_config.json') RUNTIME_FILES = ('runner.ps1', 'audit_config.json')
CONSOLE_TEMPLATE = 'console-templates/host_audit_hardeningkitty_hardeningkitty.html'
_IS_WINDOWS = os.name == 'nt'
# Old package versions included this file. It is no longer required or trusted. # Old package versions included this file. It is no longer required or trusted.
LEGACY_FILES = ('package-manifest.json',) LEGACY_FILES = ('package-manifest.json',)
@@ -202,7 +200,6 @@ def install():
# A security operation can change ACLs. Verify readability and all # A security operation can change ACLs. Verify readability and all
# checksums AFTER the final ACL change, before replacing a working install. # checksums AFTER the final ACL change, before replacing a working install.
_verify_vendor(staging, runtime=True) _verify_vendor(staging, runtime=True)
_install_console_template(source)
mkdirs(REPORT_ROOT) mkdirs(REPORT_ROOT)
_secure_directory(REPORT_ROOT) _secure_directory(REPORT_ROOT)
if isdir(INSTALL_ROOT): if isdir(INSTALL_ROOT):
@@ -227,29 +224,6 @@ def install():
(manifest['upstream_commit'], len(manifest['files']))) (manifest['upstream_commit'], len(manifest['files'])))
def _install_console_template(source):
"""Install the WAPT Console view on Windows using WAPT setuphelpers paths."""
if not _IS_WINDOWS:
return
template_source = makepath(source, *CONSOLE_TEMPLATE.split('/'))
if not isfile(template_source):
raise RuntimeError('WAPT Console audit template is missing from the package.')
# WAPT setuphelpers exposes programfiles32 as the x86 Program Files path.
template_dir = makepath(programfiles32, 'wapt', 'templates')
mkdirs(template_dir)
target = makepath(template_dir, os.path.basename(CONSOLE_TEMPLATE))
staged = target + '.new-' + uuid.uuid4().hex
try:
# setuphelpers filecopyto stages on the destination volume; os.replace
# swaps the template atomically and leaves an existing file intact if
# copying fails.
filecopyto(template_source, staged)
os.replace(staged, target)
finally:
if isfile(staged):
remove_file(staged)
def uninstall(): def uninstall():
if os.path.lexists(INSTALL_ROOT): if os.path.lexists(INSTALL_ROOT):
if not _owned_install(INSTALL_ROOT): if not _owned_install(INSTALL_ROOT):
+6 -32
View File
@@ -34,7 +34,6 @@ setuphelpers_stub.system32 = lambda: os.path.join(os.environ.get('SystemRoot', '
setuphelpers_stub.run = lambda *args, **kwargs: '' setuphelpers_stub.run = lambda *args, **kwargs: ''
setuphelpers_stub.wget = lambda *args, **kwargs: (_ for _ in ()).throw( setuphelpers_stub.wget = lambda *args, **kwargs: (_ for _ in ()).throw(
AssertionError('unexpected network download in synthetic tests')) AssertionError('unexpected network download in synthetic tests'))
setuphelpers_stub.programfiles32 = '/synthetic/Program Files (x86)'
sys.modules.setdefault('setuphelpers', setuphelpers_stub) sys.modules.setdefault('setuphelpers', setuphelpers_stub)
spec = importlib.util.spec_from_file_location('wapt_hardeningkitty_setup', ROOT / 'setup.py') spec = importlib.util.spec_from_file_location('wapt_hardeningkitty_setup', ROOT / 'setup.py')
pkg = importlib.util.module_from_spec(spec) pkg = importlib.util.module_from_spec(spec)
@@ -76,9 +75,6 @@ def make_source(root):
(root / 'setup.py').write_text('# synthetic setup\n', encoding='utf-8') (root / 'setup.py').write_text('# synthetic setup\n', encoding='utf-8')
(root / 'runner.ps1').write_text('Invoke-HardeningKitty -Mode Audit\n', encoding='utf-8') (root / 'runner.ps1').write_text('Invoke-HardeningKitty -Mode Audit\n', encoding='utf-8')
(root / 'audit_config.json').write_text('{}\n', encoding='utf-8') (root / 'audit_config.json').write_text('{}\n', encoding='utf-8')
template = root / pkg.CONSOLE_TEMPLATE
template.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(ROOT / pkg.CONSOLE_TEMPLATE, template)
asset_root = root / 'vendor' asset_root = root / 'vendor'
assets = {x: ('sample ' + x).encode('utf-8') for x in vendor.REQUIRED} assets = {x: ('sample ' + x).encode('utf-8') for x in vendor.REQUIRED}
assets['HardeningKitty.psd1'] = b"@{\n ModuleVersion = '0.9.5'\n}\n" assets['HardeningKitty.psd1'] = b"@{\n ModuleVersion = '0.9.5'\n}\n"
@@ -348,34 +344,14 @@ class PackageTests(unittest.TestCase):
def test_console_template_matches_schema_and_uses_escaped_tags(self): def test_console_template_matches_schema_and_uses_escaped_tags(self):
template = (ROOT / 'console-templates' / template = (ROOT / 'console-templates' /
'host_audit_hardeningkitty_hardeningkitty.html').read_text(encoding='utf-8') 'host_audit_hardeningkitty_hardeningkitty.html').read_text(encoding='utf-8')
# WAPT wraps the audit JSON under `value`; host metadata stays at root. self.assertIn('{{#Items categories}}', template)
self.assertIn('{{#value.summary}}', template) self.assertIn('{{#Items controls}}', template)
self.assertIn('{{#Items value.categories}}', template) self.assertIn('{{error.code}}', template)
self.assertIn('{{#Items value.controls}}', template) self.assertIn('{{error.description}}', template)
self.assertIn('{{#value.error}}', template) self.assertIn('{{summary.expected}}', template)
self.assertIn('{{code}}', template)
self.assertIn('{{description}}', template)
self.assertIn('{{checked}}', template)
self.assertIn('{{computer_fqdn}}', template)
self.assertNotIn('{{{', template) self.assertNotIn('{{{', template)
self.assertNotIn('<script', template.lower()) self.assertNotIn('<script', template.lower())
def test_windows_install_copies_console_template_using_wapt_path(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
source = make_source(root / 'package')
prior = (pkg._IS_WINDOWS, pkg.programfiles32)
try:
pkg._IS_WINDOWS = True
pkg.programfiles32 = str(root / 'Program Files (x86)')
pkg._install_console_template(str(source))
installed = (root / 'Program Files (x86)' / 'wapt' / 'templates' /
'host_audit_hardeningkitty_hardeningkitty.html')
self.assertEqual(installed.read_bytes(),
(source / pkg.CONSOLE_TEMPLATE).read_bytes())
finally:
pkg._IS_WINDOWS, pkg.programfiles32 = prior
def test_structured_error_does_not_publish_exception_details(self): def test_structured_error_does_not_publish_exception_details(self):
events = [] events = []
class FakeWapt: class FakeWapt:
@@ -564,9 +540,7 @@ class PackageTests(unittest.TestCase):
verify.verify_source(source) verify.verify_source(source)
archive = Path(tmp, 'synthetic.wapt') archive = Path(tmp, 'synthetic.wapt')
with zipfile.ZipFile(archive, 'w') as zf: with zipfile.ZipFile(archive, 'w') as zf:
for name in ('setup.py', 'runner.ps1', 'audit_config.json', for name in ('setup.py', 'runner.ps1', 'audit_config.json', 'package-manifest.json'):
'console-templates/host_audit_hardeningkitty_hardeningkitty.html',
'package-manifest.json'):
zf.write(source / name, name) zf.write(source / name, name)
zf.write(source / 'WAPT' / 'control', 'WAPT/control') zf.write(source / 'WAPT' / 'control', 'WAPT/control')
for path in (source / 'vendor').rglob('*'): for path in (source / 'vendor').rglob('*'):
-3
View File
@@ -114,9 +114,6 @@ class AuditWaptTest(unittest.TestCase):
'publish_to_wapt':True,'retain_audit_runs':3,'timeout_seconds':120, 'publish_to_wapt':True,'retain_audit_runs':3,'timeout_seconds':120,
'max_findings_in_log':10, 'max_findings_in_log':10,
})) }))
template = self.source/'console-templates'/'host_audit_hardeningkitty_hardeningkitty.html'
template.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(WORK/'console-templates'/'host_audit_hardeningkitty_hardeningkitty.html', template)
self.source.joinpath('package-manifest.json').write_text('{"stale":true}') self.source.joinpath('package-manifest.json').write_text('{"stale":true}')
(self.source/'setup.py').write_text('# synthetic setup\n') (self.source/'setup.py').write_text('# synthetic setup\n')
(self.source/'tools').mkdir() (self.source/'tools').mkdir()
+1 -4
View File
@@ -19,12 +19,9 @@ except ImportError:
UPSTREAM_COMMIT = _vendor_module.UPSTREAM_COMMIT UPSTREAM_COMMIT = _vendor_module.UPSTREAM_COMMIT
REQUIRED = _vendor_module.REQUIRED REQUIRED = _vendor_module.REQUIRED
CONSOLE_TEMPLATE = 'console-templates/host_audit_hardeningkitty_hardeningkitty.html' PACKAGE_FILES = ('setup.py', 'WAPT/control', 'runner.ps1', 'audit_config.json', 'vendor/vendor-manifest.json')
PACKAGE_FILES = ('setup.py', 'WAPT/control', 'runner.ps1', 'audit_config.json',
CONSOLE_TEMPLATE, 'vendor/vendor-manifest.json')
REQUIRED_WAPT = ( REQUIRED_WAPT = (
'setup.py', 'WAPT/control', 'runner.ps1', 'audit_config.json', 'package-manifest.json', 'setup.py', 'WAPT/control', 'runner.ps1', 'audit_config.json', 'package-manifest.json',
CONSOLE_TEMPLATE,
'vendor/HardeningKitty.psm1', 'vendor/HardeningKitty.psm1',
'vendor/HardeningKitty.psd1', 'vendor/vendor-manifest.json', 'vendor/HardeningKitty.psd1', 'vendor/vendor-manifest.json',
) )