test(fleet): normalize env wrapper options
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -131,17 +131,117 @@ function markdownLinkViolations(
|
|||||||
return violations;
|
return violations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function commandBasename(token: string): string {
|
||||||
|
return token.slice(token.lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizedCommandTokens(segment: string): string[] {
|
||||||
|
const tokens = segment
|
||||||
|
.trim()
|
||||||
|
.replace(/^(?:[$#>]\s*)/, '')
|
||||||
|
.split(/\s+/)
|
||||||
|
.filter((token): boolean => token !== '');
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while (index < tokens.length) {
|
||||||
|
const wrapper = commandBasename(tokens[index] ?? '');
|
||||||
|
if (wrapper === 'env') {
|
||||||
|
index += 1;
|
||||||
|
while (index < tokens.length) {
|
||||||
|
const token = tokens[index] ?? '';
|
||||||
|
if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) {
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (/^(?:-u|--unset|-C|--chdir)$/.test(token)) {
|
||||||
|
index += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (/^(?:-u|--unset=|-C|--chdir=)/.test(token)) {
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (/^(?:-S|--split-string)$/.test(token)) {
|
||||||
|
index += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (token.startsWith('-')) {
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (wrapper === 'command') {
|
||||||
|
index += 1;
|
||||||
|
while ((tokens[index] ?? '').startsWith('-')) index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens.slice(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
function containsPrivilegedCommand(source: string): boolean {
|
||||||
|
const privilegedCommands = new Set([
|
||||||
|
'sudo',
|
||||||
|
'doas',
|
||||||
|
'pkexec',
|
||||||
|
'systemctl',
|
||||||
|
'service',
|
||||||
|
'mount',
|
||||||
|
'umount',
|
||||||
|
'reboot',
|
||||||
|
'shutdown',
|
||||||
|
'poweroff',
|
||||||
|
'halt',
|
||||||
|
'chown',
|
||||||
|
'chmod',
|
||||||
|
'chroot',
|
||||||
|
'useradd',
|
||||||
|
'usermod',
|
||||||
|
'groupadd',
|
||||||
|
'visudo',
|
||||||
|
'apt',
|
||||||
|
'apt-get',
|
||||||
|
'apt-cache',
|
||||||
|
'dpkg',
|
||||||
|
'yum',
|
||||||
|
'dnf',
|
||||||
|
'rpm',
|
||||||
|
'apk',
|
||||||
|
'pacman',
|
||||||
|
'zypper',
|
||||||
|
'emerge',
|
||||||
|
'snap',
|
||||||
|
'flatpak',
|
||||||
|
'brew',
|
||||||
|
'nix-env',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return source.split(/[\n;&|]+/).some((segment): boolean => {
|
||||||
|
const tokens = normalizedCommandTokens(segment);
|
||||||
|
const command = commandBasename(tokens[0] ?? '');
|
||||||
|
if (privilegedCommands.has(command)) return true;
|
||||||
|
const argument = tokens[1] ?? '';
|
||||||
|
return (
|
||||||
|
command === 'su' &&
|
||||||
|
(/^(?:root|-|--command|-c)$/.test(argument) || argument.startsWith('--command='))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function exampleSafetyViolationKinds(source: string): string[] {
|
function exampleSafetyViolationKinds(source: string): string[] {
|
||||||
const kinds = new Set<string>();
|
const kinds = new Set<string>();
|
||||||
const sensitiveKey = /(?:secret|token|password|credential|MOSAIC_AGENT_COMMAND)/i;
|
const sensitiveKey = /(?:secret|token|password|credential|MOSAIC_AGENT_COMMAND)/i;
|
||||||
const credentialFormat =
|
const credentialFormat =
|
||||||
/(?:\bAKIA[0-9A-Z]{16}\b|\bAIza[0-9A-Za-z_-]{35}\b|\bgh[pousr]_[A-Za-z0-9]{20,}\b|\bgithub_pat_[A-Za-z0-9_]{20,}\b|\bglpat-[A-Za-z0-9_-]{20,}\b|\bnpm_[A-Za-z0-9]{20,}\b|\bsk-ant-(?:api\d{2}-)?[A-Za-z0-9_-]{20,}\b|\bsk-proj-[A-Za-z0-9_-]{20,}\b|\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b|\bxox[baprs]-[A-Za-z0-9-]{10,}\b|\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b|\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b|-----BEGIN [A-Z ]*PRIVATE KEY-----|\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s/:]+:[^\s/@]+@)/;
|
/(?:\bAKIA[0-9A-Z]{16}\b|\bAIza[0-9A-Za-z_-]{35}\b|\bgh[pousr]_[A-Za-z0-9]{20,}\b|\bgithub_pat_[A-Za-z0-9_]{20,}\b|\bglpat-[A-Za-z0-9_-]{20,}\b|\bnpm_[A-Za-z0-9]{20,}\b|\bsk-ant-(?:api\d{2}-)?[A-Za-z0-9_-]{20,}\b|\bsk-proj-[A-Za-z0-9_-]{20,}\b|\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b|\bxox[baprs]-[A-Za-z0-9-]{10,}\b|\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b|\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b|-----BEGIN [A-Z ]*PRIVATE KEY-----|\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s/:]+:[^\s/@]+@)/;
|
||||||
const privilegedCommand =
|
|
||||||
/(?:^|[\n;&|])\s*(?:[$#>]\s*)?(?:(?:\/(?:[A-Za-z0-9._+-]+\/)*?)?(?:env|command)\s+(?:(?:-{1,2}[^\s]+|[A-Za-z_][A-Za-z0-9_]*=[^\s]+)\s+)*?)*(?:\/(?:[A-Za-z0-9._+-]+\/)*?)?(?:(?:sudo|doas|pkexec)\s+|su\s+(?:root\b|-|--command\b|-c\b)|(?:systemctl|service|mount|umount|reboot|shutdown|poweroff|halt|chown|chmod|chroot|useradd|usermod|groupadd|visudo|apt|apt-get|apt-cache|dpkg|yum|dnf|rpm|apk|pacman|zypper|emerge|snap|flatpak|brew|nix-env)\s+)/m;
|
|
||||||
|
|
||||||
if (sensitiveKey.test(source)) kinds.add('sensitive-key');
|
if (sensitiveKey.test(source)) kinds.add('sensitive-key');
|
||||||
if (credentialFormat.test(source)) kinds.add('credential-format');
|
if (credentialFormat.test(source)) kinds.add('credential-format');
|
||||||
if (privilegedCommand.test(source)) kinds.add('privileged-command');
|
if (containsPrivilegedCommand(source)) kinds.add('privileged-command');
|
||||||
if (/\b(?:Tess|Ultron)\b/.test(source)) kinds.add('identity');
|
if (/\b(?:Tess|Ultron)\b/.test(source)) kinds.add('identity');
|
||||||
return [...kinds].sort();
|
return [...kinds].sort();
|
||||||
}
|
}
|
||||||
@@ -189,6 +289,17 @@ const UNSAFE_EXAMPLE_FIXTURES = [
|
|||||||
expected: 'privileged-command',
|
expected: 'privileged-command',
|
||||||
source: '/usr/bin/env -i /usr/bin/command -- /usr/bin/apt-get install example',
|
source: '/usr/bin/env -i /usr/bin/command -- /usr/bin/apt-get install example',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
expected: 'privileged-command',
|
||||||
|
source: '/usr/bin/env -u FOO /usr/bin/apt-get install example',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: 'privileged-command',
|
||||||
|
source: 'env --unset FOO /usr/bin/apt-get install example',
|
||||||
|
},
|
||||||
|
{ expected: 'privileged-command', source: 'env -S apt-get install example' },
|
||||||
|
{ expected: 'privileged-command', source: 'reboot' },
|
||||||
|
{ expected: 'privileged-command', source: 'su --command=/bin/sh' },
|
||||||
{ expected: 'privileged-command', source: 'su root' },
|
{ expected: 'privileged-command', source: 'su root' },
|
||||||
{ expected: 'privileged-command', source: '/usr/sbin/chroot /srv/example' },
|
{ expected: 'privileged-command', source: '/usr/sbin/chroot /srv/example' },
|
||||||
{ expected: 'credential-format', source: ['ghp_', 'a'.repeat(36)].join('') },
|
{ expected: 'credential-format', source: ['ghp_', 'a'.repeat(36)].join('') },
|
||||||
|
|||||||
Reference in New Issue
Block a user