@pathbit/agentdevkit 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/.pbai4devs/COMPATIBILIDADE.md +6 -0
  2. package/.pbai4devs/INSTRUCTIONS.md +3 -0
  3. package/.pbai4devs/agents/README.md +19 -0
  4. package/.pbai4devs/agents/auditor-seguranca/AGENT.md +20 -0
  5. package/.pbai4devs/agents/auditor-seguranca/antigravity.yaml +8 -0
  6. package/.pbai4devs/agents/auditor-seguranca/claude.yaml +5 -0
  7. package/.pbai4devs/agents/auditor-seguranca/cursor.yaml +5 -0
  8. package/.pbai4devs/agents/auditor-seguranca/gemini.yaml +6 -0
  9. package/.pbai4devs/agents/auditor-seguranca/github.yaml +5 -0
  10. package/.pbai4devs/agents/auditor-seguranca/kimi-code.yaml +5 -0
  11. package/.pbai4devs/agents/auditor-seguranca/mimocode.yaml +8 -0
  12. package/.pbai4devs/agents/auditor-seguranca/opencode.yaml +11 -0
  13. package/.pbai4devs/agents/documentador/AGENT.md +19 -0
  14. package/.pbai4devs/agents/documentador/antigravity.yaml +8 -0
  15. package/.pbai4devs/agents/documentador/claude.yaml +5 -0
  16. package/.pbai4devs/agents/documentador/cursor.yaml +5 -0
  17. package/.pbai4devs/agents/documentador/gemini.yaml +6 -0
  18. package/.pbai4devs/agents/documentador/github.yaml +5 -0
  19. package/.pbai4devs/agents/documentador/kimi-code.yaml +5 -0
  20. package/.pbai4devs/agents/documentador/mimocode.yaml +8 -0
  21. package/.pbai4devs/agents/documentador/opencode.yaml +11 -0
  22. package/.pbai4devs/agents/implementador/AGENT.md +20 -0
  23. package/.pbai4devs/agents/implementador/antigravity.yaml +8 -0
  24. package/.pbai4devs/agents/implementador/claude.yaml +5 -0
  25. package/.pbai4devs/agents/implementador/cursor.yaml +5 -0
  26. package/.pbai4devs/agents/implementador/gemini.yaml +6 -0
  27. package/.pbai4devs/agents/implementador/github.yaml +5 -0
  28. package/.pbai4devs/agents/implementador/kimi-code.yaml +5 -0
  29. package/.pbai4devs/agents/implementador/mimocode.yaml +8 -0
  30. package/.pbai4devs/agents/implementador/opencode.yaml +11 -0
  31. package/.pbai4devs/agents/planejador/AGENT.md +19 -0
  32. package/.pbai4devs/agents/planejador/antigravity.yaml +8 -0
  33. package/.pbai4devs/agents/planejador/claude.yaml +5 -0
  34. package/.pbai4devs/agents/planejador/cursor.yaml +5 -0
  35. package/.pbai4devs/agents/planejador/gemini.yaml +6 -0
  36. package/.pbai4devs/agents/planejador/github.yaml +5 -0
  37. package/.pbai4devs/agents/planejador/kimi-code.yaml +5 -0
  38. package/.pbai4devs/agents/planejador/mimocode.yaml +8 -0
  39. package/.pbai4devs/agents/planejador/opencode.yaml +11 -0
  40. package/.pbai4devs/agents/validador/AGENT.md +19 -0
  41. package/.pbai4devs/agents/validador/antigravity.yaml +8 -0
  42. package/.pbai4devs/agents/validador/claude.yaml +5 -0
  43. package/.pbai4devs/agents/validador/cursor.yaml +5 -0
  44. package/.pbai4devs/agents/validador/gemini.yaml +6 -0
  45. package/.pbai4devs/agents/validador/github.yaml +5 -0
  46. package/.pbai4devs/agents/validador/kimi-code.yaml +5 -0
  47. package/.pbai4devs/agents/validador/mimocode.yaml +8 -0
  48. package/.pbai4devs/agents/validador/opencode.yaml +11 -0
  49. package/.pbai4devs/commands/README.md +13 -0
  50. package/.pbai4devs/commands/atualizar-documentacao/COMMAND.md +17 -0
  51. package/.pbai4devs/commands/auditar-seguranca/COMMAND.md +25 -0
  52. package/.pbai4devs/commands/implementar-entrega/COMMAND.md +20 -0
  53. package/.pbai4devs/commands/planejar-entrega/COMMAND.md +17 -0
  54. package/.pbai4devs/commands/preparar-seguranca/COMMAND.md +22 -0
  55. package/.pbai4devs/commands/validar-entrega/COMMAND.md +18 -0
  56. package/.pbai4devs/commands/verificar-dependencias/COMMAND.md +18 -0
  57. package/.pbai4devs/commands/verificar-segredos/COMMAND.md +19 -0
  58. package/.pbai4devs/external-skills/CATALOG.json +39 -1
  59. package/.pbai4devs/external-skills/README.md +13 -0
  60. package/.pbai4devs/rules/README.md +4 -0
  61. package/.pbai4devs/rules/execucao-local/RULE.md +20 -0
  62. package/.pbai4devs/rules/execucao-local/cursor.yaml +4 -0
  63. package/.pbai4devs/rules/seguranca/RULE.md +19 -0
  64. package/.pbai4devs/rules/seguranca/cursor.yaml +4 -0
  65. package/.pbai4devs/scripts/README.md +1 -0
  66. package/.pbai4devs/scripts/auditar-seguranca/README.md +57 -0
  67. package/.pbai4devs/scripts/auditar-seguranca/SCRIPT.mjs +411 -0
  68. package/.pbai4devs/scripts/auditar-seguranca/database-zip.mjs +143 -0
  69. package/.pbai4devs/scripts/auditar-seguranca/rules/javascript.yml +50 -0
  70. package/.pbai4devs/scripts/auditar-seguranca/tests/SMOKE.mjs +74 -0
  71. package/.pbai4devs/scripts/auditar-seguranca/tests/TEST.mjs +247 -0
  72. package/.pbai4devs/scripts/auditar-seguranca/tests/zip-fixture.mjs +45 -0
  73. package/.pbai4devs/scripts/lib/native-release.mjs +193 -0
  74. package/.pbai4devs/scripts/preparar-ferramentas/README.md +8 -2
  75. package/.pbai4devs/scripts/preparar-ferramentas/SCRIPT.mjs +46 -16
  76. package/.pbai4devs/scripts/preparar-ferramentas/tests/TEST.mjs +2 -0
  77. package/.pbai4devs/scripts/preparar-ferramentas/tests/native-release.test.mjs +103 -0
  78. package/.pbai4devs/skills/README.md +10 -2
  79. package/.pbai4devs/skills/projeto/preparar-ferramentas/SKILL.md +5 -1
  80. package/.pbai4devs/skills/seguranca/REFERENCE.md +104 -0
  81. package/.pbai4devs/skills/seguranca/corrigir-vulnerabilidade/SKILL.md +27 -0
  82. package/.pbai4devs/skills/seguranca/modelar-ameacas/SKILL.md +25 -0
  83. package/.pbai4devs/skills/seguranca/revisar-autorizacao/SKILL.md +29 -0
  84. package/.pbai4devs/skills/seguranca/revisar-seguranca/SKILL.md +27 -0
  85. package/.pbai4devs/templates/README.md +2 -0
  86. package/.pbai4devs/templates/revisao-seguranca/TEMPLATE.md +33 -0
  87. package/.pbai4devs/tools/README.md +11 -3
  88. package/.pbai4devs/tools/gitleaks/README.md +22 -0
  89. package/.pbai4devs/tools/gitleaks/SCRIPT.mjs +5 -0
  90. package/.pbai4devs/tools/gitleaks/TOOL.json +67 -0
  91. package/.pbai4devs/tools/opengrep/README.md +22 -0
  92. package/.pbai4devs/tools/opengrep/SCRIPT.mjs +5 -0
  93. package/.pbai4devs/tools/opengrep/TOOL.json +71 -0
  94. package/.pbai4devs/tools/osv-scanner/README.md +23 -0
  95. package/.pbai4devs/tools/osv-scanner/SCRIPT.mjs +5 -0
  96. package/.pbai4devs/tools/osv-scanner/TOOL.json +70 -0
  97. package/CHANGELOG.md +17 -0
  98. package/README.en.md +18 -5
  99. package/README.es.md +19 -6
  100. package/README.md +16 -3
  101. package/docs/README.md +9 -5
  102. package/docs/guides/README.md +3 -1
  103. package/docs/guides/cli.md +3 -0
  104. package/docs/guides/installation.md +61 -11
  105. package/docs/guides/prerequisites.md +123 -0
  106. package/docs/guides/resources.md +48 -1
  107. package/docs/guides/security-references.md +97 -0
  108. package/docs/guides/security.md +32 -0
  109. package/docs/guides/tools-and-testing.md +2 -1
  110. package/docs/guides/troubleshooting.md +23 -7
  111. package/docs/maintainers/README.md +1 -1
  112. package/docs/maintainers/maintenance.md +15 -4
  113. package/docs/maintainers/packages.md +45 -13
  114. package/docs/product/prd.md +4 -1
  115. package/docs/product/roadmap.md +4 -0
  116. package/docs/specs/README.md +3 -0
  117. package/docs/specs/dual-registry/SPEC.md +43 -0
  118. package/docs/specs/security-ecosystem/README.md +9 -0
  119. package/docs/specs/security-ecosystem/SPEC.md +53 -0
  120. package/docs/specs/v0.0.10/README.md +9 -0
  121. package/docs/specs/v0.0.10/SPEC.md +42 -0
  122. package/package.json +1 -1
@@ -6,6 +6,7 @@ import { spawnSync } from 'node:child_process';
6
6
  import { randomUUID } from 'node:crypto';
7
7
  import { hostname } from 'node:os';
8
8
  import { projectRoot, requireNode, isMain } from '../lib/runtime.mjs';
9
+ import { validateNativeDownload, nativeRelease, validateNativeRelease, installNative, checkNative, assertNativeVersion } from '../lib/native-release.mjs';
9
10
 
10
11
  const registry = 'https://registry.npmjs.org/';
11
12
  const versionPattern = /^\d+\.\d+\.\d+(?:-[\w.-]+)?$/;
@@ -29,9 +30,13 @@ export function validateToolConfig(name, value) {
29
30
  if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name) || value?.name !== name) fail(`Nome de ferramenta invalido: ${name}`);
30
31
  if (typeof value.description !== 'string' || !value.description.trim() || value.description.includes('\0')) fail(`Descricao ausente ou invalida: ${name}`);
31
32
  const download = value.download;
32
- if (download?.provider !== 'npm' || download.registry !== registry || download.channel !== 'latest') fail(`Download nao suportado: ${name}`);
33
- if (!/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/.test(download.package || '') || !/^[\w.-]+\/[\w.-]+$/.test(download.repository || '')) fail(`Origem invalida: ${name}`);
33
+ if (!['npm', 'github-release'].includes(download?.provider)) fail(`Download nao suportado: ${name}`);
34
+ if (download.provider === 'npm') {
35
+ if (download.registry !== registry || download.channel !== 'latest') fail(`Download nao suportado: ${name}`);
36
+ if (!/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/.test(download.package || '') || !/^[\w.-]+\/[\w.-]+$/.test(download.repository || '')) fail(`Origem invalida: ${name}`);
37
+ }
34
38
  if (!/^[a-z][a-z0-9-]*$/.test(value.group || '') || !Array.isArray(value.platforms) || !value.platforms.length || new Set(value.platforms).size !== value.platforms.length || value.platforms.some(item => !/^(?:darwin|linux|win32)-(?:arm64|x64)$/.test(item))) fail(`Grupo/plataformas invalidos: ${name}`);
39
+ if (download.provider === 'github-release') validateNativeDownload(download, value.platforms);
35
40
  if (!Array.isArray(value.probe) || !value.probe.length || value.probe.some(item => typeof item !== 'string' || item.includes('\0')) || (value.probeInput !== undefined && (typeof value.probeInput !== 'string' || value.probeInput.includes('\0')))) fail(`Verificacao invalida: ${name}`);
36
41
  if (value.binary !== undefined && (typeof value.binary !== 'string' || !/^[\w.-]+$/.test(value.binary))) fail(`Executavel invalido: ${name}`);
37
42
  if (value.executables !== undefined) {
@@ -72,7 +77,7 @@ export function toolActions(name, entry) {
72
77
  validateToolConfig(name, entry);
73
78
  const descriptions = {
74
79
  install: 'Instala ou reutiliza uma instalacao saudavel.',
75
- update: 'Consulta latest e atualiza com rollback em caso de falha.',
80
+ update: entry.download.provider === 'github-release' ? 'Aplica a versao revisada do catalogo com rollback.' : 'Consulta latest e atualiza com rollback em caso de falha.',
76
81
  check: 'Executa o probe local sem instalar nem consultar latest.',
77
82
  info: 'Mostra configuracao, plataforma, runtime e versao registrada.',
78
83
  run: 'Executa o CLI instalado com os argumentos informados.',
@@ -128,7 +133,8 @@ export function loadCatalog(root = projectRoot) {
128
133
  return catalog;
129
134
  }
130
135
 
131
- export function validateRelease(name, entry, release) {
136
+ export function validateRelease(name, entry, release, platform = platformKey()) {
137
+ if (entry.download.provider === 'github-release') return validateNativeRelease(entry, release, platform);
132
138
  const expected = entry.download.package;
133
139
  const repository = typeof release.repository === 'string' ? release.repository : release.repository?.url;
134
140
  if (release.name !== expected || !versionPattern.test(release.version || '')) fail(`Nome/versao invalido no registro: ${name}`);
@@ -165,6 +171,9 @@ export function binaryInvocation(prefix, name, args = [], binaryName = name.spli
165
171
 
166
172
  export function toolEnvironment(entry, local, runtime) {
167
173
  const environment = Object.assign(Object.create(null), process.env);
174
+ if (entry.download?.provider === 'github-release') {
175
+ for (const key of Object.keys(environment)) if (/token|secret|password|(?:^|_)auth(?:_|$)|^(?:semgrep|opengrep)_/i.test(key)) delete environment[key];
176
+ }
168
177
  const set = (key, value) => {
169
178
  if (process.platform === 'win32') for (const existing of Object.keys(environment)) if (existing.toUpperCase() === key.toUpperCase()) delete environment[existing];
170
179
  environment[key] = value;
@@ -184,10 +193,13 @@ export function toolEnvironment(entry, local, runtime) {
184
193
  }
185
194
 
186
195
  function execute(prefix, entry, args, capture = false, input, environment, runtime) {
187
- const [file, options] = binaryInvocation(prefix, entry.download.package, args, entry.binary || entry.name, runtime.file);
196
+ const native = entry.download.provider === 'github-release';
197
+ const [file, options] = native ? [checkNative(prefix, entry, runtime.platform || platformKey()).file, args]
198
+ : binaryInvocation(prefix, entry.download.package, args, entry.binary || entry.name, runtime.file);
188
199
  const result = spawnSync(file, options, { stdio: capture ? 'pipe' : 'inherit', cwd: capture ? prefix : undefined, input, env: environment, encoding: 'utf8', timeout: capture ? 30000 : undefined, windowsHide: true });
189
200
  if (result.error) throw result.error;
190
201
  if (capture && result.status !== 0) fail(`${entry.name}: ${result.stderr?.trim().slice(0, 400) || result.stdout?.trim().slice(0, 400) || `falha ${result.status}`}`, result.status ?? 1);
202
+ if (capture && native) assertNativeVersion(`${result.stdout || ''}\n${result.stderr || ''}`, entry.download.version);
191
203
  return result.status ?? 1;
192
204
  }
193
205
 
@@ -215,11 +227,13 @@ export class ToolManager {
215
227
  this.catalog = catalog ?? loadCatalog(this.root);
216
228
  for (const [name, entry] of Object.entries(this.catalog)) validateToolConfig(name, entry);
217
229
  this.fetchRelease = fetchRelease || (async (name, entry) => {
230
+ if (entry.download.provider === 'github-release') return nativeRelease(entry, this.target);
218
231
  const response = await fetch(`${entry.download.registry}${encodeURIComponent(entry.download.package)}/${entry.download.channel}`, { signal: AbortSignal.timeout(20000) });
219
232
  if (!response.ok) fail(`Registro indisponivel: HTTP ${response.status}`);
220
233
  return response.json();
221
234
  });
222
- this.installPackage = install || ((prefix, packageName, version, entry, runtime) => {
235
+ this.installPackage = install || (async (prefix, packageName, version, entry, runtime) => {
236
+ if (entry.download.provider === 'github-release') return installNative(prefix, entry, this.target);
223
237
  const environment = toolEnvironment(entry, this.local(entry.name), runtime);
224
238
  const result = spawnSync(runtime.file, [this.npm(runtime, environment), 'install', '--prefix', prefix, '--cache', join(this.home, '.cache/npm'), '--registry', entry.download.registry, '--ignore-scripts', '--omit=dev', '--no-audit', '--no-fund', '--save-exact', `${packageName}@${version}`], {
225
239
  cwd: prefix, encoding: 'utf8', timeout: 180000,
@@ -236,7 +250,7 @@ export class ToolManager {
236
250
  const entry = this.entry(name);
237
251
  if (!entry.platforms.includes(this.target)) fail(`Plataforma nao suportada por ${name}: ${this.target}`);
238
252
  requireNode(24, this.nodeVersion);
239
- return { file: process.execPath, version: process.version };
253
+ return { file: process.execPath, version: process.version, platform: this.target };
240
254
  }
241
255
  preflight(names) {
242
256
  const issues = [];
@@ -298,8 +312,13 @@ export class ToolManager {
298
312
  }
299
313
  check(name) {
300
314
  const entry = this.entry(name); const runtime = this.runtime(name); const info = this.current(name);
301
- const pkg = json(join(info.prefix, 'node_modules', entry.download.package, 'package.json'));
302
- if (pkg.name !== entry.download.package || pkg.version !== info.version) fail(`Versao local divergente: ${name}`);
315
+ if (entry.download.provider === 'github-release') {
316
+ const receipt = checkNative(info.prefix, entry, this.target);
317
+ if (receipt.version !== info.version || receipt.binarySha256 !== info.binarySha256) fail(`Versao local divergente: ${name}`);
318
+ } else {
319
+ const pkg = json(join(info.prefix, 'node_modules', entry.download.package, 'package.json'));
320
+ if (pkg.name !== entry.download.package || pkg.version !== info.version) fail(`Versao local divergente: ${name}`);
321
+ }
303
322
  execute(info.prefix, entry, entry.probe, true, entry.probeInput, toolEnvironment(entry, this.local(name), runtime), runtime);
304
323
  return info;
305
324
  }
@@ -399,7 +418,7 @@ export class ToolManager {
399
418
  renameSync(storagePath(this.root, temporary, 'file'), storagePath(this.root, join(local, 'CURRENT.json'), 'file'));
400
419
  }
401
420
  async updateLocked(name) {
402
- const entry = this.entry(name); const runtime = this.runtime(name); const release = validateRelease(name, entry, await this.fetchRelease(name, entry));
421
+ const entry = this.entry(name); const runtime = this.runtime(name); const release = validateRelease(name, entry, await this.fetchRelease(name, entry), this.target);
403
422
  const { local } = this.storage(name);
404
423
  const target = storagePath(this.root, join(local, 'versions', `${release.version}-${this.target}`), 'directory');
405
424
  let installed;
@@ -409,14 +428,21 @@ export class ToolManager {
409
428
  const stage = mkdtempSync(join(local, '.stage-'));
410
429
  const temporary = storagePath(this.root, join(local, `CURRENT.${randomUUID()}.json`), 'file'); let previous; let moved = false;
411
430
  try {
412
- this.installPackage(stage, entry.download.package, release.version, entry, runtime);
431
+ if (entry.download.provider === 'github-release') {
432
+ for (const location of Object.values(entry.envPaths || {})) mkdirSync(storagePath(this.root, join(local, location), 'directory'), { recursive: true });
433
+ }
434
+ await this.installPackage(stage, entry.download.package, release.version, entry, runtime);
413
435
  this.storage(name); storagePath(this.root, stage, 'directory');
414
- const pkg = json(join(stage, 'node_modules', entry.download.package, 'package.json')); const lock = json(join(stage, 'package-lock.json'));
415
- if (pkg.name !== entry.download.package || pkg.version !== release.version || lock.packages?.[`node_modules/${entry.download.package}`]?.integrity !== release.dist.integrity) fail('Pacote instalado nao corresponde ao registro.');
416
- prepareExecutables(stage, entry, this.target);
436
+ let receipt;
437
+ if (entry.download.provider === 'github-release') receipt = checkNative(stage, entry, this.target);
438
+ else {
439
+ const pkg = json(join(stage, 'node_modules', entry.download.package, 'package.json')); const lock = json(join(stage, 'package-lock.json'));
440
+ if (pkg.name !== entry.download.package || pkg.version !== release.version || lock.packages?.[`node_modules/${entry.download.package}`]?.integrity !== release.dist.integrity) fail('Pacote instalado nao corresponde ao registro.');
441
+ prepareExecutables(stage, entry, this.target);
442
+ }
417
443
  execute(stage, entry, entry.probe, true, entry.probeInput, toolEnvironment(entry, local, runtime), runtime);
418
444
  this.storage(name); storagePath(this.root, target, 'directory');
419
- const info = { name, package: entry.download.package, version: release.version, platform: this.target, node: runtime.version, nodePath: runtime.file, source: entry.source, tarball: release.dist.tarball, integrity: release.dist.integrity, checkedAt: new Date().toISOString() };
445
+ const info = { name, ...(receipt ? { provider: 'github-release', binarySha256: receipt.binarySha256, archiveSha256: receipt.archiveSha256 } : { package: entry.download.package }), version: release.version, platform: this.target, node: runtime.version, nodePath: runtime.file, source: entry.source, tarball: receipt ? release.url : release.dist.tarball, integrity: receipt ? `sha256-${Buffer.from(receipt.archiveSha256, 'hex').toString('base64')}` : release.dist.integrity, checkedAt: new Date().toISOString() };
420
446
  writeFileSync(storagePath(this.root, temporary, 'file'), `${JSON.stringify(info, null, 2)}\n`, { flag: 'wx' });
421
447
  this.launchers(name);
422
448
  if (existsSync(target)) { previous = storagePath(this.root, `${target}.previous-${randomUUID()}`, 'directory'); renameSync(storagePath(this.root, target, 'directory'), previous); }
@@ -425,7 +451,11 @@ export class ToolManager {
425
451
  return { ...info, layout: 'local', prefix: target, changed: true };
426
452
  } finally { rmSync(storagePath(this.root, stage, 'directory'), { recursive: true, force: true }); rmSync(storagePath(this.root, temporary, 'file'), { force: true }); }
427
453
  }
428
- run(name, args) { const entry = this.entry(name); const runtime = this.runtime(name); return execute(this.current(name).prefix, entry, args, false, undefined, toolEnvironment(entry, this.local(name), runtime), runtime); }
454
+ run(name, args) {
455
+ const entry = this.entry(name), runtime = this.runtime(name), current = this.current(name);
456
+ if (entry.download.provider === 'github-release' && checkNative(current.prefix, entry, this.target).binarySha256 !== current.binarySha256) fail(`Recibo local divergente: ${name}`);
457
+ return execute(current.prefix, entry, args, false, undefined, toolEnvironment(entry, this.local(name), runtime), runtime);
458
+ }
429
459
  }
430
460
 
431
461
  const help = 'Uso: setup [all|grupo|nome]; [install|update|check|info] [base|all|grupo|nome]; list; unlock <nome>; run <nome> [argumentos]; --tool <nome> <acao> [argumentos].';
@@ -8,6 +8,7 @@ import { hostname } from 'node:os';
8
8
  import { ToolManager, platformKey, validateRelease, validateToolConfig, loadCatalog, main, toolEnvironment, binaryInvocation, toolActions, toolWrapper } from '../SCRIPT.mjs';
9
9
  import { requireNode } from '../../lib/runtime.mjs';
10
10
  import './bootstrap.test.mjs';
11
+ import './native-release.test.mjs';
11
12
 
12
13
  const project = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..');
13
14
  const tool = (name = 'test-tool', group = 'base') => ({ name, description: 'Ferramenta da fixture.', group, source: `https://github.com/owner/${name}`, download: { provider: 'npm', package: name, registry: 'https://registry.npmjs.org/', repository: `owner/${name}`, channel: 'latest' }, platforms: [platformKey()], scripts: { entry: 'SCRIPT.mjs' }, probe: ['--version'] });
@@ -44,6 +45,7 @@ function fixture(t, catalog = { 'test-tool': tool() }, options = {}) {
44
45
  copyFileSync(join(project, '.pbai4devs/scripts/preparar-ferramentas/SCRIPT.mjs'), join(common, 'SCRIPT.mjs'));
45
46
  mkdirSync(join(root, '.pbai4devs/scripts/lib'), { recursive: true });
46
47
  copyFileSync(join(project, '.pbai4devs/scripts/lib/runtime.mjs'), join(root, '.pbai4devs/scripts/lib/runtime.mjs'));
48
+ copyFileSync(join(project, '.pbai4devs/scripts/lib/native-release.mjs'), join(root, '.pbai4devs/scripts/lib/native-release.mjs'));
47
49
  const state = { version: '1.0.0', installs: 0, fetches: 0, fail: false, tamper: false, broken: false, noBin: false };
48
50
  const manager = new ToolManager({ root, catalog, fetchRelease: async name => { state.fetches++; return release(state.version, name); }, install(prefix, name, version) { state.installs++; if (state.fail) throw new Error('download de prova falhou'); packageFiles(prefix, name, version, state); }, ...options });
49
51
  return { root, manager, state, local: join(root, '.pbai4devs/tools/test-tool/.local') };
@@ -0,0 +1,103 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { gzipSync, deflateRawSync } from 'node:zlib';
4
+ import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, rmSync, symlinkSync, existsSync } from 'node:fs';
5
+ import { dirname, join, resolve } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { nativeHash, nativeRelease, validateNativeDownload, validateNativeRelease, downloadNative, extractNative, installNative, checkNative, assertNativeVersion } from '../../lib/native-release.mjs';
8
+ import { ToolManager, platformKey, toolEnvironment } from '../SCRIPT.mjs';
9
+
10
+ const project = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..');
11
+ function fixture(t) { const dir = join(project, '.agent-tests'); mkdirSync(dir, { recursive: true }); const root = mkdtempSync(join(dir, 'native tools ')); t.after(() => rmSync(root, { recursive: true, force: true })); return root; }
12
+ function config(bytes = Buffer.from('#!/bin/sh\necho 1.2.3\n'), version = '1.2.3') {
13
+ return { name: 'native-test', description: 'Native fixture.', group: 'security', source: 'https://github.com/owner/repo',
14
+ platforms: [platformKey()], scripts: { entry: 'SCRIPT.mjs' }, probe: ['--version'],
15
+ download: { provider: 'github-release', repository: 'owner/repo', channel: 'reviewed', version, tag: `v${version}`,
16
+ assets: { [platformKey()]: { file: 'tool.bin', format: 'raw', binary: 'tool', sha256: nativeHash(bytes) } } } };
17
+ }
18
+ function tar(entries) {
19
+ const chunks = [];
20
+ for (const { name, bytes = Buffer.from('binary'), type = '0' } of entries) {
21
+ const header = Buffer.alloc(512); header.write(name, 0, 100); header.write('0000755\0', 100); header.write('0000000\0', 108); header.write('0000000\0', 116);
22
+ header.write(bytes.length.toString(8).padStart(11, '0') + '\0', 124); header.write('00000000000\0', 136); header.fill(32, 148, 156); header.write(type, 156); header.write('ustar\0', 257);
23
+ header.write([...header].reduce((a, b) => a + b, 0).toString(8).padStart(6, '0') + '\0 ', 148);
24
+ chunks.push(header, bytes, Buffer.alloc((512 - bytes.length % 512) % 512));
25
+ }
26
+ return gzipSync(Buffer.concat([...chunks, Buffer.alloc(1024)]));
27
+ }
28
+ function crc32(bytes) { let crc = 0xffffffff; for (const b of bytes) { crc ^= b; for (let i = 0; i < 8; i++) crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1)); } return (crc ^ 0xffffffff) >>> 0; }
29
+ function zip(entries) {
30
+ const locals = [], centrals = []; let cursor = 0;
31
+ for (const { name, bytes = Buffer.from('binary'), mode = 0o100755, method = 8 } of entries) {
32
+ const filename = Buffer.from(name), compressed = method === 8 ? deflateRawSync(bytes) : bytes, crc = crc32(bytes);
33
+ const local = Buffer.alloc(30); local.writeUInt32LE(0x04034b50); local.writeUInt16LE(20, 4); local.writeUInt16LE(method, 8); local.writeUInt32LE(crc, 14); local.writeUInt32LE(compressed.length, 18); local.writeUInt32LE(bytes.length, 22); local.writeUInt16LE(filename.length, 26);
34
+ const central = Buffer.alloc(46); central.writeUInt32LE(0x02014b50); central.writeUInt16LE(3 << 8 | 20, 4); central.writeUInt16LE(20, 6); central.writeUInt16LE(method, 10); central.writeUInt32LE(crc, 16); central.writeUInt32LE(compressed.length, 20); central.writeUInt32LE(bytes.length, 24); central.writeUInt16LE(filename.length, 28); central.writeUInt32LE((mode << 16) >>> 0, 38); central.writeUInt32LE(cursor, 42);
35
+ locals.push(local, filename, compressed); centrals.push(central, filename); cursor += local.length + filename.length + compressed.length;
36
+ }
37
+ const central = Buffer.concat(centrals), end = Buffer.alloc(22); end.writeUInt32LE(0x06054b50); end.writeUInt16LE(entries.length, 8); end.writeUInt16LE(entries.length, 10); end.writeUInt32LE(central.length, 12); end.writeUInt32LE(cursor, 16);
38
+ return Buffer.concat([...locals, central, end]);
39
+ }
40
+ const asset = (bytes, format, binary = 'tool') => ({ format, binary, sha256: nativeHash(bytes) });
41
+
42
+ test('native release requires reviewed pins and exact platform assets', () => {
43
+ const entry = config(); assert.equal(validateNativeDownload(entry.download, entry.platforms), entry.download);
44
+ const release = nativeRelease(entry, platformKey()); assert.equal(validateNativeRelease(entry, release, platformKey()), release);
45
+ for (const change of [{ channel: 'latest' }, { tag: 'master' }, { version: '1.2.3-rc.1' }, { repository: '../evil' }, { assets: {} }]) assert.throws(() => validateNativeDownload({ ...entry.download, ...change }, entry.platforms));
46
+ assert.throws(() => validateNativeRelease(entry, { ...release, url: 'https://evil.example/tool' }, platformKey()));
47
+ const invalid = config(); invalid.download.assets[platformKey()].binary = '../escape'; assert.throws(() => validateNativeDownload(invalid.download, invalid.platforms));
48
+ assert.throws(() => assertNativeVersion('version 1.2.30', '1.2.3')); assert.throws(() => assertNativeVersion('version 1.2.3-rc.1', '1.2.3')); assertNativeVersion('Tool v1.2.3\n', '1.2.3');
49
+ });
50
+
51
+ test('native download follows only anonymous official asset hosts with limits', async () => {
52
+ const seen = [];
53
+ const fetcher = async (url, options) => { seen.push({ url, options }); return seen.length === 1 ? new Response(null, { status: 302, headers: { location: 'https://release-assets.githubusercontent.com/file?signature=x' } }) : new Response('data'); };
54
+ assert.equal((await downloadNative('https://github.com/owner/repo/releases/download/v1/tool', { fetcher })).toString(), 'data');
55
+ assert.ok(seen.every(({ options }) => !Object.keys(options.headers).some(key => /authorization|token/i.test(key))));
56
+ await assert.rejects(downloadNative('http://github.com/file', { fetcher }), /Host/);
57
+ await assert.rejects(downloadNative('https://evil.example/file', { fetcher }), /GitHub/);
58
+ await assert.rejects(downloadNative('https://github.com/file', { fetcher: async () => new Response(null, { status: 302, headers: { location: 'https://evil.example/file' } }) }), /Host/);
59
+ await assert.rejects(downloadNative('https://github.com/file', { maxBytes: 2, fetcher: async () => new Response('four') }), /limite/);
60
+ await assert.rejects(downloadNative('https://github.com/file', { fetcher: async () => new Response('missing', { status: 404 }) }), /404/);
61
+ });
62
+
63
+ test('native extraction accepts exact raw/tar/zip executable and rejects traversal and links', () => {
64
+ const raw = Buffer.from('raw binary'); assert.deepEqual(extractNative(raw, asset(raw, 'raw')), raw);
65
+ for (const format of ['tar.gz', 'zip']) {
66
+ const pack = format === 'tar.gz' ? tar : zip;
67
+ const archive = pack([{ name: 'LICENSE', bytes: Buffer.from('license') }, { name: 'tool', bytes: raw }]);
68
+ assert.deepEqual(extractNative(archive, asset(archive, format)), raw);
69
+ for (const name of ['../escape', '/absolute', 'C:/drive', 'folder\\escape']) {
70
+ const bad = pack([{ name }, { name: 'tool' }]); assert.throws(() => extractNative(bad, asset(bad, format)), /Caminho/);
71
+ }
72
+ const duplicate = pack([{ name: 'tool' }, { name: 'TOOL' }]); assert.throws(() => extractNative(duplicate, asset(duplicate, format)), /duplicada/);
73
+ const link = pack([{ name: 'link', type: '2', mode: 0o120777 }, { name: 'tool' }]); assert.throws(() => extractNative(link, asset(link, format)), /Links|Link/);
74
+ assert.throws(() => extractNative(archive, { ...asset(archive, format), sha256: '0'.repeat(64) }), /SHA-256/);
75
+ assert.throws(() => extractNative(archive, asset(archive, format, 'absent')), /ausente/);
76
+ }
77
+ });
78
+
79
+ test('native receipts reject tampering and symbolic files without following them', async t => {
80
+ const root = fixture(t), bytes = Buffer.from('binary'), entry = config(bytes); const prefix = join(root, 'stage'); mkdirSync(prefix);
81
+ const receipt = await installNative(prefix, entry, platformKey(), { download: async () => bytes }); assert.equal(checkNative(prefix, entry, platformKey()).binarySha256, receipt.binarySha256);
82
+ const executable = join(prefix, receipt.executable); writeFileSync(executable, 'tampered'); assert.throws(() => checkNative(prefix, entry, platformKey()), /alterado/);
83
+ writeFileSync(executable, bytes); const outside = join(root, 'outside'); writeFileSync(outside, 'preserve'); rmSync(executable);
84
+ try { symlinkSync(outside, executable); } catch (error) { if (['EPERM', 'EACCES'].includes(error.code)) return; throw error; }
85
+ assert.throws(() => checkNative(prefix, entry, platformKey()), /simbolico/); assert.equal(readFileSync(outside, 'utf8'), 'preserve');
86
+ });
87
+
88
+ test('native manager installs, reuses without network, updates reviewed pins and rolls back', { skip: process.platform === 'win32' }, async t => {
89
+ const root = fixture(t); let bytes = Buffer.from('#!/bin/sh\nif [ "$1" = "exit" ]; then exit 37; fi\necho 1.2.3\n'), installs = 0, fail = false;
90
+ let entry = config(bytes); const manager = new ToolManager({ root, catalog: { 'native-test': entry }, install: async prefix => { installs++; if (fail) throw Error('download failed'); await installNative(prefix, entry, platformKey(), { download: async () => bytes }); } });
91
+ const installed = await manager.install(entry.name); assert.equal(installed.version, '1.2.3'); assert.equal(manager.check(entry.name).version, '1.2.3'); assert.equal(manager.run(entry.name, ['exit']), 37);
92
+ manager.fetchRelease = async () => { throw Error('unexpected network'); }; assert.equal((await manager.install(entry.name)).changed, false); assert.equal(installs, 1);
93
+ const old = readFileSync(join(manager.local(entry.name), 'CURRENT.json'));
94
+ bytes = Buffer.from('#!/bin/sh\necho 2.0.0\n'); entry = config(bytes, '2.0.0'); manager.catalog[entry.name] = entry; manager.fetchRelease = async () => nativeRelease(entry, platformKey()); fail = true;
95
+ await assert.rejects(manager.update(entry.name), /download failed/); assert.deepEqual(readFileSync(join(manager.local(entry.name), 'CURRENT.json')), old);
96
+ fail = false; assert.equal((await manager.update(entry.name)).version, '2.0.0'); assert.equal(manager.check(entry.name).version, '2.0.0');
97
+ assert.ok(!existsSync(join(manager.local(entry.name), '.update-lock')));
98
+ });
99
+
100
+ test('native environment removes unrelated credentials while preserving host settings', () => {
101
+ const saved = process.env.NATIVE_TEST_TOKEN; process.env.NATIVE_TEST_TOKEN = 'secret';
102
+ try { assert.equal(toolEnvironment(config(), '/tmp/local').NATIVE_TEST_TOKEN, undefined); } finally { if (saved === undefined) delete process.env.NATIVE_TEST_TOKEN; else process.env.NATIVE_TEST_TOKEN = saved; }
103
+ });
@@ -4,13 +4,19 @@ description: Finalidade e criação de skills compartilhadas.
4
4
 
5
5
  # Skills
6
6
 
7
- São procedimentos reutilizáveis, organizados em `git`, `projeto`, `produto` e
8
- `specs`. Cada skill usa `<grupo>/<nome>/SKILL.md` com nome e descrição no YAML.
7
+ São procedimentos reutilizáveis, organizados por assunto. Cada skill usa
8
+ `<grupo>/<nome>/SKILL.md` com nome e descrição no YAML. A skill orienta decisões;
9
+ o agente responsável pode acionar comandos, scripts e outros perfis conforme
10
+ as capacidades do cliente.
9
11
 
10
12
  - `git`: operações de versionamento.
11
13
  - `projeto`: configuração, criação e manutenção dos recursos.
12
14
  - `produto`: PRD, experiência e design técnico.
13
15
  - `specs`: especificações, roadmap e implementação.
16
+ - `seguranca`: [revisão](seguranca/revisar-seguranca/SKILL.md),
17
+ [autorização](seguranca/revisar-autorizacao/SKILL.md),
18
+ [ameaças](seguranca/modelar-ameacas/SKILL.md) e
19
+ [correção](seguranca/corrigir-vulnerabilidade/SKILL.md).
14
20
 
15
21
  Use `criar-skill` quando uma tarefa recorrente precisar de decisões próprias;
16
22
  use `criar-recurso` para encontrar um fluxo existente antes de criar outro.
@@ -21,4 +27,6 @@ Use [proximos-passos](projeto/proximos-passos/SKILL.md) para orientar a
21
27
  continuidade conforme a fase e as pendências reais.
22
28
 
23
29
  O [guia compartilhado](../INSTRUCTIONS.md) orienta o uso das skills.
30
+ As skills de segurança integram a instalação do kit; os scanners exigem
31
+ [preparo explícito](../commands/preparar-seguranca/COMMAND.md).
24
32
  Ao alterar o inventário, sincronize os índices e apontamentos locais.
@@ -24,7 +24,8 @@ instalador compartilhado.
24
24
  No preparo inicial, execute `preparar-ferramentas setup` pelo seletor:
25
25
  instala e verifica todas as ferramentas compatíveis, sem atualizar as saudáveis.
26
26
  Aceita seleção por nome/grupo; relate falhas e itens não aplicáveis.
27
- Para buscar versões novas, `update` consulta `latest` oficial.
27
+ Para npm, `update` consulta `latest` oficial; ferramentas nativas de segurança
28
+ seguem o pin revisado em `TOOL.json`, sem atualização silenciosa para outro binário.
28
29
  `install` reutiliza uma instalação saudável; `check` verifica sem rede;
29
30
  `info` mostra a configuração; `run <nome> [argumentos]` executa sem instalar.
30
31
  Sem ação, mostre ajuda. Não interprete ausência de argumentos como instalação.
@@ -41,6 +42,9 @@ Em `skills`, use `find` ou `add <origem> --list`; incorporações passam por
41
42
  O shell virtual não substitui testes reais. Só ative proxy, certificados,
42
43
  serviços ou gravação quando necessários à tarefa e com dependências preparadas.
43
44
 
45
+ Para segurança, use [preparar-seguranca](../../../commands/preparar-seguranca/COMMAND.md).
46
+ Preparar o CLI e atualizar bases são operações separadas da análise offline.
47
+
44
48
  Antes de usar agent-desktop, leia `skills get desktop` e `skills get platform`
45
49
  da versão instalada e confira `status`. Para agent-browser, leia
46
50
  `skills get core` e `--help` da versão instalada e
@@ -0,0 +1,104 @@
1
+ ---
2
+ description: Segurança com scanners locais, triagem e provas de controles.
3
+ ---
4
+
5
+ # Segurança local
6
+
7
+ A instalação do kit inclui skills, regras, comandos e perfis de segurança.
8
+ Os scanners são preparados por uma ação explícita; os arquivos de instrução
9
+ não iniciam auditorias, serviços ou downloads em segundo plano.
10
+
11
+ ## Como os componentes trabalham juntos
12
+
13
+ O comando [auditar-seguranca][audit] organiza o trabalho. A
14
+ [skill de revisão][review] define como analisar e o [auditor][auditor] faz a
15
+ triagem contextual. O script executa ferramentas e produz evidências; as
16
+ [regras][rules] orientam todas as etapas. Veja o [catálogo de comandos](../../commands/README.md).
17
+
18
+ | Ferramenta | Pergunta que ajuda a responder |
19
+ | --- | --- |
20
+ | [Gitleaks][gitleaks] | Há indícios de segredos nos arquivos analisados? |
21
+ | [OSV-Scanner][osv] | A base local conhece falhas nas versões das dependências? |
22
+ | [Opengrep][opengrep] | O código corresponde aos padrões das regras locais? |
23
+
24
+ As ferramentas executam localmente e não exigem conta ou assinatura.
25
+ Versões revisadas e suas origens ficam nos `TOOL.json`. Downloads públicos de
26
+ binários e bases são separados da análise. A política do cliente/modelo de IA
27
+ continua sendo própria; não coloque valores secretos no contexto da conversa.
28
+
29
+ ## Preparar e executar
30
+
31
+ Use Node.js 24+ e o projeto autorizado. O fluxo de
32
+ [preparar-seguranca][prepare] instala os scanners e confere seu funcionamento:
33
+
34
+ ```console
35
+ node .pbai4devs/scripts/preparar-ferramentas/SCRIPT.mjs setup security
36
+ ```
37
+
38
+ Para dependências, baixe a base dos ecossistemas realmente utilizados. Exemplo
39
+ para npm; substitua por `Go` ou pela seleção suportada que corresponda ao projeto:
40
+
41
+ ```console
42
+ node .pbai4devs/scripts/auditar-seguranca/SCRIPT.mjs update-data --ecosystems npm
43
+ node .pbai4devs/scripts/auditar-seguranca/SCRIPT.mjs check
44
+ node .pbai4devs/scripts/auditar-seguranca/SCRIPT.mjs run
45
+ ```
46
+
47
+ `run` usa os três checks: `secrets`, `dependencies` e `sast`. Para limitar,
48
+ use [verificar-segredos][secrets] ou [verificar-dependencias][dependencies].
49
+ A análise usa dados locais; base ausente não autoriza enviar o projeto a uma API.
50
+ Confira no relatório a versão da ferramenta, a base e o escopo efetivamente lido.
51
+
52
+ ## O que ainda precisa ser provado
53
+
54
+ O [artigo sobre falhas recorrentes][article] motiva os temas abaixo. As
55
+ verificações dependem da arquitetura e não equivalem a uma certificação.
56
+
57
+ | Tema | Prova necessária no projeto |
58
+ | --- | --- |
59
+ | Autorização no servidor | API direta recusa visitante e papel insuficiente. |
60
+ | Acesso por identificador | Usuário A não lê ou altera o recurso de B. |
61
+ | Isolamento dos dados | Policies/RLS ou Security Rules restringem o acesso. |
62
+ | Segredos | Credenciais privadas não chegam a fontes, bundles ou logs. |
63
+ | Entradas e abuso | Testes de validação, saída, upload e limites do fluxo. |
64
+
65
+ RLS é um controle de PostgreSQL usado pelo Supabase; Firebase tem Security Rules.
66
+ SDKs privilegiados podem atravessar esses controles e precisam de autorização
67
+ no servidor. Esconder um botão de administrador não protege a API.
68
+
69
+ Use [revisar-autorizacao][authorization] com identidades sintéticas distintas,
70
+ testes negativos e dados locais. Para entradas, prefira consultas parametrizadas,
71
+ codificação de saída por contexto e limites de upload; sanitização genérica não
72
+ resolve todos os casos. Teste a interface no navegador quando ela existir.
73
+ Sem aplicação executável, registre essas provas como **não verificadas**.
74
+
75
+ ## Interpretar e corrigir
76
+
77
+ O runner retorna `0` sem achados, `1` com achados e `2` em falha ou verificação
78
+ incompleta. Leia o estado de cada check: não aplicável e não executado não
79
+ significam aprovado. Regras locais e formatos suportados limitam a cobertura.
80
+
81
+ O relatório fica em `.agent-tests/security/<execucao>/report.json`, sem valores
82
+ secretos. O auditor distingue suspeitas, falhas confirmadas e falsos positivos.
83
+ Use [modelar-ameacas][threats] para novos fluxos e
84
+ [corrigir-vulnerabilidade][fix] para reparar a causa com teste de regressão.
85
+ Uma credencial real exposta precisa de revogação pelo responsável; não a teste
86
+ contra serviços externos. Feche a entrega com [revisão independente][gate].
87
+
88
+ [Skills](../README.md) · [Ferramentas](../../tools/README.md)
89
+
90
+ [audit]: ../../commands/auditar-seguranca/COMMAND.md
91
+ [review]: ../../skills/seguranca/revisar-seguranca/SKILL.md
92
+ [auditor]: ../../agents/auditor-seguranca/AGENT.md
93
+ [rules]: ../../rules/seguranca/RULE.md
94
+ [gitleaks]: ../../tools/gitleaks/README.md
95
+ [osv]: ../../tools/osv-scanner/README.md
96
+ [opengrep]: ../../tools/opengrep/README.md
97
+ [prepare]: ../../commands/preparar-seguranca/COMMAND.md
98
+ [secrets]: ../../commands/verificar-segredos/COMMAND.md
99
+ [dependencies]: ../../commands/verificar-dependencias/COMMAND.md
100
+ [authorization]: ../../skills/seguranca/revisar-autorizacao/SKILL.md
101
+ [threats]: ../../skills/seguranca/modelar-ameacas/SKILL.md
102
+ [fix]: ../../skills/seguranca/corrigir-vulnerabilidade/SKILL.md
103
+ [gate]: ../../commands/revisar-entrega/COMMAND.md
104
+ [article]: https://manodeyvin.com.br/p/5-vacilacoes-de-seguranca-que-a-ia
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: corrigir-vulnerabilidade
3
+ description: Corrige um achado validado e prova que a causa foi removida.
4
+ ---
5
+
6
+ # Corrigir vulnerabilidade
7
+
8
+ Receba o achado e sua evidência de [revisar-seguranca](../revisar-seguranca/SKILL.md).
9
+ Confirme o caminho de abuso e o escopo autorizado. Esclareça dúvidas e apresente
10
+ o plano antes de editar, respeitando aprovações já dadas.
11
+
12
+ Corrija a causa, preserve o contrato legítimo e acrescente um teste de regressão
13
+ que falhe antes e passe depois. Não silencie regra ou exclua arquivo apenas
14
+ para deixar o scanner verde; documente falsos positivos com justificativa.
15
+
16
+ Use [implementar-spec](../../specs/implementar-spec/SKILL.md) quando houver spec
17
+ e [verificar-trabalho](../../projeto/verificar-trabalho/SKILL.md) para as provas.
18
+ Repita o scanner relevante e o cenário original. Mudanças web exigem navegador;
19
+ autorização exige a matriz de [permissões](../revisar-autorizacao/SKILL.md).
20
+
21
+ Se houver segredo real, não o reproduza. Informe o responsável para revogação
22
+ e rotação pelo canal apropriado; remover do código não invalida a credencial.
23
+ Não altere contas, histórico Git ou serviços externos sem escopo explícito.
24
+
25
+ Saída: correção, teste, risco residual e documentação atualizada. Feche com
26
+ [revisar-entrega](../../../commands/revisar-entrega/COMMAND.md), incluindo
27
+ revisão independente e evidências ignoradas em `.agent-tests/security/`.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: modelar-ameacas
3
+ description: Identifica ativos, fronteiras de confiança e ameaças do escopo aprovado.
4
+ ---
5
+
6
+ # Modelar ameaças
7
+
8
+ Leia produto, design e código relacionados. Reúna primeiro as dúvidas sobre
9
+ dados, atores, operações privilegiadas e limites do ambiente. Registre o que
10
+ é fato, hipótese ou informação ausente; não invente arquitetura.
11
+
12
+ Mapeie os ativos, entradas, fluxos e fronteiras de confiança. Para cada ameaça,
13
+ descreva pré-condição, caminho de abuso, impacto, controle e teste observável.
14
+ Priorize o que o desenho realmente permite: acesso entre usuários, elevação
15
+ de privilégio, vazamento, injeção e abuso de recursos.
16
+
17
+ Use o [modelo de revisão](../../../templates/revisao-seguranca/TEMPLATE.md)
18
+ como apoio e o [auditor](../../../agents/auditor-seguranca/AGENT.md) para revisão.
19
+ Se o projeto precisar de um documento permanente, combine seu destino com o
20
+ usuário e siga [atualizar-documentacao](../../projeto/atualizar-documentacao/SKILL.md).
21
+ Rascunhos e evidências ficam em `.agent-tests/security/`.
22
+
23
+ Saída: ameaças priorizadas, controles existentes, lacunas e critérios de teste.
24
+ O modelo orienta [revisar-seguranca](../revisar-seguranca/SKILL.md); não comprova
25
+ que os controles foram implementados ou testados.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: revisar-autorizacao
3
+ description: Verifica identidade, permissões por recurso e isolamento entre usuários.
4
+ ---
5
+
6
+ # Revisar autorização
7
+
8
+ Identifique sujeitos, papéis, recursos e operações permitidas. Leia rotas,
9
+ middleware, políticas de dados e testes; não deduza autorização pela interface.
10
+ Se o contrato não existir, reúna as dúvidas antes de propor mudanças.
11
+
12
+ Confira autenticação e autorização no servidor em cada operação sensível,
13
+ incluindo IDs manipuláveis, operações em lote e ações administrativas.
14
+ Em PostgreSQL/Supabase, revise RLS, policies, papéis e acessos privilegiados.
15
+ Em Firebase, revise Security Rules e SDKs privilegiados; são controles distintos.
16
+
17
+ Com contas sintéticas no ambiente local autorizado, prove no mínimo:
18
+
19
+ - Visitante não autenticado recebe a recusa prevista.
20
+ - Usuário A acessa seu recurso e não acessa o de B trocando o identificador.
21
+ - Usuário comum não obtém a ação administrativa pela API direta.
22
+ - Listagens, alterações e exclusões obedecem ao mesmo isolamento.
23
+
24
+ Use testes de API e, quando houver interface, navegador conforme
25
+ [verificar-trabalho](../../projeto/verificar-trabalho/SKILL.md).
26
+ Não crie contas reais nem use dados de produção para essa prova.
27
+ Sem aplicação executável ou identidades de teste, registre **não verificado**.
28
+ Entregue matriz de permissões, resultados e achados sem segredos em
29
+ `.agent-tests/security/`, usando o [modelo](../../../templates/revisao-seguranca/TEMPLATE.md).
@@ -0,0 +1,27 @@
1
+ ---
2
+ name: revisar-seguranca
3
+ description: Revisa riscos de segurança com análise local, contexto e provas.
4
+ ---
5
+
6
+ # Revisar segurança
7
+
8
+ Defina o escopo: mudança ou projeto, dados sensíveis, stack e ambiente autorizado.
9
+ Leia as regras de [segurança](../../../rules/seguranca/RULE.md) e
10
+ [execução local](../../../rules/execucao-local/RULE.md). Não amplie o alvo.
11
+
12
+ Use [auditar-seguranca](../../../commands/auditar-seguranca/COMMAND.md) para
13
+ os scanners disponíveis e o [auditor](../../../agents/auditor-seguranca/AGENT.md)
14
+ para interpretar os resultados. Uma ferramenta ausente ou base indisponível
15
+ gera pendência; resultado vazio não substitui análise de contexto.
16
+
17
+ Revise também autenticação, autorização por recurso, isolamento de dados,
18
+ segredos e entradas conforme o [guia](../REFERENCE.md).
19
+ Use [revisar-autorizacao](../revisar-autorizacao/SKILL.md) para permissões e
20
+ [modelar-ameacas](../modelar-ameacas/SKILL.md) quando houver novas fronteiras.
21
+
22
+ Registre achado, evidência, impacto, confiança e estado da triagem, sem valores
23
+ secretos. Diferencie vulnerabilidade confirmada, suspeita e falso positivo.
24
+ Prove cenários de API pelo terminal e fluxos web no navegador local autorizado,
25
+ seguindo [verificar-trabalho](../../projeto/verificar-trabalho/SKILL.md).
26
+ Salve o relatório em `.agent-tests/security/`; não declare o produto seguro
27
+ com base apenas em scanners. Encaminhe correções à skill correspondente.
@@ -28,6 +28,7 @@ enquanto o usuário estiver preparando somente a estrutura dos agentes.
28
28
  | [Revisão de entrega][revisao] | Implementação | Antes de commit/merge. |
29
29
  | [Release][release], [CHANGELOG][changelog] | Primeira entrega | Publicar. |
30
30
  | [SECURITY][security] | Suporte público | Política/suporte mudar. |
31
+ | [Revisão de segurança][security-review] | Análise autorizada | Ameaças e provas. |
31
32
  | [Comando][comando] | Recurso agêntico | Entrada ou fluxo mudar. |
32
33
 
33
34
  Antes, inventarie e leia os documentos existentes com `atualizar-documentacao`.
@@ -65,4 +66,5 @@ Modelos, configurações e relatórios não são espelhados nas pastas dos agent
65
66
  [release]: release/TEMPLATE.md
66
67
  [changelog]: changelog/TEMPLATE.md
67
68
  [security]: seguranca/TEMPLATE.md
69
+ [security-review]: revisao-seguranca/TEMPLATE.md
68
70
  [comando]: comando/TEMPLATE.md
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: Modelo de contexto, ameaças, achados e provas de segurança.
3
+ status: modelo
4
+ ---
5
+
6
+ # Revisão de segurança
7
+
8
+ Preencha com fatos do escopo autorizado. Resultados e rascunhos ficam em
9
+ `.agent-tests/security/`; combine o destino de documentação permanente.
10
+ Este modelo complementa o relatório JSON dos scanners, sem substituir suas provas.
11
+
12
+ ## Contexto
13
+
14
+ Alvo, alteração, ambiente, ativos, atores, operações e fronteiras de confiança.
15
+ Registre fontes, hipóteses e dúvidas; não preencha lacunas com suposições.
16
+
17
+ ## Ameaças e controles
18
+
19
+ | Ameaça | Pré-condição | Impacto | Controle existente | Teste necessário |
20
+ | --- | --- | --- | --- | --- |
21
+ | A definir | A confirmar | A confirmar | Evidência | Resultado esperado |
22
+
23
+ ## Achados
24
+
25
+ | ID | Local | Evidência sem segredo | Confiança | Estado | Próxima ação |
26
+ | --- | --- | --- | --- | --- | --- |
27
+ | SEC-001 | Arquivo/linha | Evidência | A avaliar | A triar | Responsável |
28
+
29
+ ## Validação
30
+
31
+ Critério, comando ou cenário, resultado, caminho da prova e limitações.
32
+ Separe o que passou, falhou, não se aplica e não foi executado.
33
+ Registre revisão independente e risco residual antes de concluir.