mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-26 02:06:49 +00:00
feat: add Docker label audit across Fleet and Stack views (#1531)
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import type { Request } from 'express';
|
||||
import type { LabelInventoryOptions } from '../services/LabelInventoryService';
|
||||
import { requireAdmin } from '../middleware/tierGates';
|
||||
|
||||
/** Parse ?reveal=1; full values only when the caller is an admin. */
|
||||
export function labelInventoryOptionsFromRequest(req: Request): LabelInventoryOptions {
|
||||
const wantsReveal = req.query.reveal === '1' || req.query.reveal === 'true';
|
||||
if (!wantsReveal) return { revealSecrets: false };
|
||||
// requireAdmin is synchronous guard; routes call it before building inventory when reveal is requested.
|
||||
return { revealSecrets: true };
|
||||
}
|
||||
|
||||
/** Returns false and sends 403 when reveal was requested but caller is not admin. */
|
||||
export function requireRevealAdmin(req: Request, res: import('express').Response): boolean {
|
||||
const wantsReveal = req.query.reveal === '1' || req.query.reveal === 'true';
|
||||
if (!wantsReveal) return true;
|
||||
return requireAdmin(req, res);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { isLikelySecretKey } from './secretClassification';
|
||||
|
||||
export const REDACTED_SENTINEL = '[redacted]';
|
||||
|
||||
/**
|
||||
* Compound single-token segments specific to Docker/Compose labels that the generic
|
||||
* env classifier does not split (e.g. Traefik `basicauth`/`digestauth` middleware keys,
|
||||
* whose value carries inline `user:passwordhash` credentials).
|
||||
*/
|
||||
const SECRET_LABEL_SEGMENTS = new Set(['BASICAUTH', 'DIGESTAUTH']);
|
||||
|
||||
/** True when a Docker/Compose label key likely carries a sensitive value. */
|
||||
export function isLikelySecretLabelKey(rawKey: string): boolean {
|
||||
if (isLikelySecretKey(rawKey)) return true;
|
||||
const segments = rawKey.trim().toUpperCase().split(/[^A-Z0-9]+/).filter(Boolean);
|
||||
return segments.some(seg => SECRET_LABEL_SEGMENTS.has(seg));
|
||||
}
|
||||
|
||||
export function redactLabelValue(key: string, value: string, revealSecrets: boolean): { value: string; redacted?: boolean } {
|
||||
if (revealSecrets || !isLikelySecretLabelKey(key)) {
|
||||
return { value };
|
||||
}
|
||||
return { value: REDACTED_SENTINEL, redacted: true };
|
||||
}
|
||||
@@ -16,6 +16,7 @@ const SECRET_SEGMENTS = new Set([
|
||||
'SECRET', 'SECRETS',
|
||||
'TOKEN', 'KEY', 'APIKEY',
|
||||
'CREDENTIAL', 'CREDENTIALS', 'AUTH',
|
||||
'BASIC',
|
||||
]);
|
||||
|
||||
/** Connection strings whose value is sensitive but whose segments are innocuous. */
|
||||
|
||||
Reference in New Issue
Block a user