fix(resources): harden Resource Explorer with auth, validation, design, and UX fixes (#527)

- Sanitize error messages in all delete/prune/create/inspect endpoints
  to prevent Docker internals from leaking to the frontend
- Add CIDR, IPv4, and Docker resource ID input validation
- Add requirePaid gate to network topology endpoint
- Add invalidateNodeCaches after image/volume/network mutations
- Fix design system violations: card borders, destructive button variant,
  visible DialogDescription, overflow-auto replaced with ScrollArea,
  hardcoded Tailwind colors replaced with tokens
- Gate purge button behind isAdmin to prevent silent 403s
- Fix shared inspect loading state to be per-network-row
- Parse error response bodies for meaningful toast messages
- Add clipboard API fallback for non-HTTPS contexts
- Render Options section in network inspect sheet
- Add operational and diagnostic logging for resource operations
- Extend validation and DockerController test suites
- Update docs with Options field in network inspect
This commit is contained in:
Anso
2026-04-12 15:31:35 -04:00
committed by GitHub
parent a5cb316ca9
commit 4909c35e50
10 changed files with 303 additions and 52 deletions
+33
View File
@@ -39,6 +39,39 @@ export function isValidRemoteUrl(
return { valid: true, url };
}
/** Returns true when all four captured octet strings are in 0-255 range. */
function octetsInRange(a: string, b: string, c: string, d: string): boolean {
return [a, b, c, d].map(Number).every(o => o >= 0 && o <= 255);
}
/**
* Validates an IPv4 CIDR notation string (e.g. `10.0.0.0/24`).
* Checks octet ranges (0-255) and prefix length (0-32).
*/
export function isValidCidr(value: string): boolean {
const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/.exec(value);
if (!match) return false;
return octetsInRange(match[1], match[2], match[3], match[4]) && Number(match[5]) <= 32;
}
/**
* Validates a plain IPv4 address (e.g. `192.168.1.1`).
* Rejects CIDR notation; use `isValidCidr` for that.
*/
export function isValidIPv4(value: string): boolean {
const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(value);
if (!match) return false;
return octetsInRange(match[1], match[2], match[3], match[4]);
}
/**
* Validates a Docker resource ID (hex string, 12-64 characters).
* Covers both short IDs (12 chars) and full SHA256 IDs (64 chars).
*/
export function isValidDockerResourceId(id: string): boolean {
return /^[a-f0-9]{12,64}$/i.test(id);
}
/**
* Asserts that a resolved file path stays within a given base directory.
* Returns true if the path is safe, false if it escapes the base.