auto-sync: tudo-para-ia-mais-humana 2026-05-01 23:21:24

This commit is contained in:
2026-05-01 23:21:24 -03:00
parent a3a5dcd8ce
commit cdce7a8b65
15 changed files with 40381 additions and 543 deletions

View File

@@ -0,0 +1,14 @@
{
"centralPlatformFolder": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform",
"failureCount": 1,
"failures": [
{
"error": "PermissionError: [Errno 13] Permission denied: 'G:\\\\_codex-git\\\\nucleo-gestao-operacional\\\\central-de-ordem-de-servico\\\\projects\\\\15_repo_tudo-para-ia-mais-humana-platform\\\\reports\\\\MCP-GATEWAY-ACCESS-POLICY__RODADA015.md'",
"operation": "write_text",
"path": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform\\reports\\MCP-GATEWAY-ACCESS-POLICY__RODADA015.md"
}
],
"generatedAt": "2026-05-02T02:17:13+00:00",
"ok": false,
"policy": "falha de escrita central nao aborta artefatos do projeto real"
}

View File

@@ -0,0 +1,440 @@
{
"auth_scheme": "Bearer credentialRef; raw token forbidden in artifacts",
"blockers": [],
"checks": [
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "todos os probes usaram POST",
"rule_id": "http.method.post",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "todos os probes usaram application/json",
"rule_id": "header.content-type.json",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "User-Agent operacional aplicado",
"rule_id": "header.user-agent.codex",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "bearer usado como credencial de probe e redigido nos artefatos",
"rule_id": "auth.bearer.present-redacted",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "WAF nao bloqueou os probes atuais; HTTP/runtime classificados separadamente",
"rule_id": "waf.classification.explicit",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "traceId e auditId presentes em todos os probes",
"rule_id": "evidence.trace-audit-required",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "hashes de request/response presentes",
"rule_id": "evidence.hashes-required",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "nenhum formato de segredo bruto detectado nas evidencias",
"rule_id": "redaction.no-secret-shapes",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "regra institucional materializada no artefato de politica",
"rule_id": "rate-limit.default",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "regra institucional materializada no artefato de politica",
"rule_id": "retention.logs",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "regra institucional materializada no artefato de politica",
"rule_id": "transit.required-fields",
"status": "passed"
},
{
"evidence_refs": [
"evidence-a75a27e0669c49da1db8b615",
"evidence-af37a8d489b0038a7a6b5575",
"evidence-3f0e3b9f829c7ff912b335d0"
],
"next_action": "manter regra como gate de release",
"reason": "regra institucional materializada no artefato de politica",
"rule_id": "governance.plugin-not-operational-path",
"status": "passed"
}
],
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"generated_at": "2026-05-02T02:17:13+00:00",
"liveReady": true,
"log_retention_days": 30,
"policy_version": "mcp-gateway-access-policy.v1",
"probes": [
{
"audit_id": "audit-a75a27e0669c49da1db8b615",
"authorization_present": true,
"authorization_redacted": true,
"content_type": "application/json",
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"evidence_id": "evidence-a75a27e0669c49da1db8b615",
"http_status": 200,
"method": "POST",
"observed_at": "2026-05-02T02:17:12+00:00",
"ok": true,
"request_hash": "3e1c8f057ac439f4b9b3eb7f8f5be9ac36323f08adc23db6fc7d51633076b79a",
"response_excerpt": {
"__truncated__": true,
"actorId": "codex.service-order-round",
"auditId": "audit:mcps-gateway:codex.service-order-round:mais_humana.rulebook.compact",
"blockers": "[]",
"consumption": "None",
"nextActions": "[]",
"ok": "True",
"organizationId": "None",
"productId": "None",
"providerId": "mais_humana",
"readiness": "None",
"sampleData": "False",
"simulated": "False",
"status": "ok",
"traceId": "trace:mcps-gateway:codex.service-order-round:mais_humana.rulebook.compact",
"userId": "None",
"workspaceId": "None"
},
"response_hash": "a75a27e0669c49da1db8b6157757c0615eed06c32674c7ed87a6db5d071359de",
"tool_id": "mais_humana.rulebook.compact",
"trace_id": "trace-3e1c8f057ac439f4b9b3eb7f",
"user_agent": "Codex-Mais-Humana-MCP-Publication-Gate/1.0"
},
{
"audit_id": "audit-af37a8d489b0038a7a6b5575",
"authorization_present": true,
"authorization_redacted": true,
"content_type": "application/json",
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"evidence_id": "evidence-af37a8d489b0038a7a6b5575",
"http_status": 200,
"method": "POST",
"observed_at": "2026-05-02T02:17:12+00:00",
"ok": true,
"request_hash": "17e7d8039c8c34e3f570b6de8b386edc1cfd0c079084b0c7013016d2c76b388c",
"response_excerpt": {
"__truncated__": true,
"actorId": "codex.service-order-round",
"auditId": "audit:mcps-gateway:codex.service-order-round:mais_humana.admin_ui.same_source",
"blockers": "[]",
"consumption": "None",
"nextActions": "[]",
"ok": "True",
"organizationId": "None",
"productId": "None",
"providerId": "mais_humana",
"readiness": "None",
"sampleData": "False",
"simulated": "False",
"status": "ok",
"traceId": "trace:mcps-gateway:codex.service-order-round:mais_humana.admin_ui.same_source",
"userId": "None",
"workspaceId": "None"
},
"response_hash": "af37a8d489b0038a7a6b5575970ec69855dd0f0e0ab09cf38b0e7658d3678195",
"tool_id": "mais_humana.admin_ui.same_source",
"trace_id": "trace-17e7d8039c8c34e3f570b6de",
"user_agent": "Codex-Mais-Humana-MCP-Publication-Gate/1.0"
},
{
"audit_id": "audit-3f0e3b9f829c7ff912b335d0",
"authorization_present": true,
"authorization_redacted": true,
"content_type": "application/json",
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"evidence_id": "evidence-3f0e3b9f829c7ff912b335d0",
"http_status": 200,
"method": "POST",
"observed_at": "2026-05-02T02:17:12+00:00",
"ok": true,
"request_hash": "dae7d91a59e37901d50c027d3a0792f697902bd4289801edb2a508f3baf177fe",
"response_excerpt": {
"__truncated__": true,
"actorId": "codex.service-order-round",
"auditId": "audit:mcps-gateway:codex.service-order-round:mais_humana.mcp_transit.ledger",
"blockers": "[]",
"consumption": "None",
"nextActions": "[]",
"ok": "True",
"organizationId": "None",
"productId": "None",
"providerId": "mais_humana",
"readiness": "None",
"sampleData": "False",
"simulated": "False",
"status": "ok",
"traceId": "trace:mcps-gateway:codex.service-order-round:mais_humana.mcp_transit.ledger",
"userId": "None",
"workspaceId": "None"
},
"response_hash": "3f0e3b9f829c7ff912b335d01afb5e78acdaa331bd984713dfca757072be6bbf",
"tool_id": "mais_humana.mcp_transit.ledger",
"trace_id": "trace-dae7d91a59e37901d50c027d",
"user_agent": "Codex-Mais-Humana-MCP-Publication-Gate/1.0"
}
],
"rate_limit_per_minute": 30,
"report_id": "mcp-gateway-access-policy-a787db3755906de2",
"required_content_type": "application/json",
"required_method": "POST",
"required_user_agent": "Codex-Mais-Humana-MCP-Publication-Gate/1.0",
"rules": [
{
"evidence_fields": [
"method",
"endpoint"
],
"failure_status": "blocked",
"kind": "http",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Toda chamada GPT/MCP deve usar POST em /v1/execute.",
"rule_id": "http.method.post",
"title": "Metodo HTTP fixo",
"validation": "Comparar metodo observado com POST."
},
{
"evidence_fields": [
"content_type"
],
"failure_status": "blocked",
"kind": "header",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Toda chamada deve enviar Content-Type application/json.",
"rule_id": "header.content-type.json",
"title": "Content-Type JSON",
"validation": "Comparar content_type observado."
},
{
"evidence_fields": [
"user_agent"
],
"failure_status": "partial",
"kind": "header",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Probes Codex devem usar User-Agent Codex-Mais-Humana-MCP-Publication-Gate/1.0.",
"rule_id": "header.user-agent.codex",
"title": "User-Agent operacional",
"validation": "Comparar User-Agent observado para separar WAF de runtime."
},
{
"evidence_fields": [
"authorization_present",
"authorization_redacted"
],
"failure_status": "blocked",
"kind": "auth",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Authorization Bearer pode ser usado no probe, mas relatorios devem guardar apenas existencia, hash e credentialRef.",
"rule_id": "auth.bearer.present-redacted",
"title": "Bearer presente e nunca persistido bruto",
"validation": "Confirmar authorization_present e authorization_redacted."
},
{
"evidence_fields": [
"http_status",
"response_excerpt"
],
"failure_status": "partial",
"kind": "waf",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "HTTP 403/1010 e bloqueios WAF devem ser separados de tool_not_found, erro de runtime e erro de contrato.",
"rule_id": "waf.classification.explicit",
"title": "Classificacao WAF explicita",
"validation": "Usar http_status e response_excerpt redigido para classificar falha."
},
{
"evidence_fields": [
"trace_id",
"audit_id",
"evidence_id"
],
"failure_status": "blocked",
"kind": "evidence",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Toda resposta aceita deve possuir traceId e auditId reais ou derivados de hash de evidencia.",
"rule_id": "evidence.trace-audit-required",
"title": "Trace e audit obrigatorios",
"validation": "Confirmar trace_id e audit_id por probe."
},
{
"evidence_fields": [
"request_hash",
"response_hash"
],
"failure_status": "blocked",
"kind": "evidence",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Toda evidencia deve guardar request_hash e response_hash sem payload sensivel bruto.",
"rule_id": "evidence.hashes-required",
"title": "Hashes de payload e resposta",
"validation": "Confirmar hashes preenchidos por probe."
},
{
"evidence_fields": [
"response_excerpt"
],
"failure_status": "blocked",
"kind": "redaction",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Evidencias nao podem conter cfat_, Authorization Bearer cru, tokens longos ou bearer numerico bruto.",
"rule_id": "redaction.no-secret-shapes",
"title": "Sem segredo bruto em evidencia",
"validation": "Varrer response_excerpt e campos textuais por formatos proibidos."
},
{
"evidence_fields": [
"rate_limit_per_minute"
],
"failure_status": "partial",
"kind": "rate_limit",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Probes automatizados devem respeitar limite padrao de 30 chamadas/minuto por ator.",
"rule_id": "rate-limit.default",
"title": "Limite operacional padrao",
"validation": "Registrar limite no contrato e bloquear suites que excedam o teto."
},
{
"evidence_fields": [
"log_retention_days"
],
"failure_status": "partial",
"kind": "retention",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Logs de evidencia operacional devem reter metadados redigidos por 30 dias.",
"rule_id": "retention.logs",
"title": "Retencao de logs",
"validation": "Registrar politica no artefato de acesso."
},
{
"evidence_fields": [
"origin",
"destination",
"tool",
"payload",
"actor",
"permission",
"result",
"traceId",
"auditId",
"timestamp"
],
"failure_status": "blocked",
"kind": "transit",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Fluxos interplataforma devem preservar origin, destination, tool, payload, actor, permission, result, traceId, auditId e timestamp.",
"rule_id": "transit.required-fields",
"title": "Ledger MCP obrigatorio",
"validation": "Validar campos exigidos no contrato de transito MCP."
},
{
"evidence_fields": [
"policy_version"
],
"failure_status": "partial",
"kind": "governance",
"owner": "tudo-para-ia-mcps-internos-plataform",
"required": true,
"requirement": "Falha ou aceite do plugin Cloudflare fica fora do diagnostico de Workers; trabalho real usa wrangler ou validacao HTTP live.",
"rule_id": "governance.plugin-not-operational-path",
"title": "Plugin Cloudflare nao substitui caminho operacional",
"validation": "Confirmar que o artefato nao transforma plugin em blocker operacional."
}
],
"secretSafe": true,
"status": "passed",
"summary": [
"Probes live avaliados: 3.",
"Probes live OK: 3/3.",
"Regras aprovadas: 12/12.",
"Bearer bruto persistido: False.",
"Falha do plugin Cloudflare nao e blocker operacional: True."
]
}

View File

@@ -8,7 +8,7 @@
"path": "G:\\_codex-git\\nucleo-gestao-operacional\\central-de-ordem-de-servico\\projects\\15_repo_tudo-para-ia-mais-humana-platform\\reports\\executivos\\MCP-PUBLICATION-GATE-MAIS-HUMANA__RODADA015.md"
}
],
"generatedAt": "2026-05-02T02:13:32+00:00",
"generatedAt": "2026-05-02T02:17:12+00:00",
"ok": false,
"policy": "falha de escrita central nao aborta artefatos do projeto real"
}

View File

@@ -149,7 +149,7 @@
"mais_humana.mcp_transit.ledger"
]
},
"generated_at": "2026-05-02T02:13:32+00:00",
"generated_at": "2026-05-02T02:17:12+00:00",
"liveReady": true,
"live_probes": [
{
@@ -158,7 +158,7 @@
"error_code": "",
"evidence_id": "evidence-a75a27e0669c49da1db8b615",
"http_status": 200,
"observed_at": "2026-05-02T02:13:32+00:00",
"observed_at": "2026-05-02T02:17:12+00:00",
"ok": true,
"response_excerpt": {
"__truncated__": true,
@@ -191,7 +191,7 @@
"error_code": "",
"evidence_id": "evidence-af37a8d489b0038a7a6b5575",
"http_status": 200,
"observed_at": "2026-05-02T02:13:32+00:00",
"observed_at": "2026-05-02T02:17:12+00:00",
"ok": true,
"response_excerpt": {
"__truncated__": true,
@@ -224,7 +224,7 @@
"error_code": "",
"evidence_id": "evidence-3f0e3b9f829c7ff912b335d0",
"http_status": 200,
"observed_at": "2026-05-02T02:13:32+00:00",
"observed_at": "2026-05-02T02:17:12+00:00",
"ok": true,
"response_excerpt": {
"__truncated__": true,
@@ -254,7 +254,7 @@
],
"localReady": true,
"provider_id": "mais_humana",
"report_id": "mcp-publication-gate-2026-05-02t0213320000",
"report_id": "mcp-publication-gate-2026-05-02t0217120000",
"status": "partial",
"summary": [
"Provider local Mais Humana pronto: True.",

View File

@@ -0,0 +1,173 @@
# Politica de acesso GPT/MCP Gateway
- report_id: `mcp-gateway-access-policy-a787db3755906de2`
- generated_at: `2026-05-02T02:17:13+00:00`
- policy_version: `mcp-gateway-access-policy.v1`
- endpoint: `https://mcps-gateway.ami-app.workers.dev/v1/execute`
- status: `passed`
- live_ready: `True`
- secret_safe: `True`
- method: `POST`
- content_type: `application/json`
- user_agent: `Codex-Mais-Humana-MCP-Publication-Gate/1.0`
- auth_scheme: `Bearer credentialRef; raw token forbidden in artifacts`
- rate_limit_per_minute: `30`
- log_retention_days: `30`
## Sumario
- Probes live avaliados: 3.
- Probes live OK: 3/3.
- Regras aprovadas: 12/12.
- Bearer bruto persistido: False.
- Falha do plugin Cloudflare nao e blocker operacional: True.
## Regras
### http.method.post
- kind: `http`
- required: `True`
- requisito: Toda chamada GPT/MCP deve usar POST em /v1/execute.
- validacao: Comparar metodo observado com POST.
### header.content-type.json
- kind: `header`
- required: `True`
- requisito: Toda chamada deve enviar Content-Type application/json.
- validacao: Comparar content_type observado.
### header.user-agent.codex
- kind: `header`
- required: `True`
- requisito: Probes Codex devem usar User-Agent Codex-Mais-Humana-MCP-Publication-Gate/1.0.
- validacao: Comparar User-Agent observado para separar WAF de runtime.
### auth.bearer.present-redacted
- kind: `auth`
- required: `True`
- requisito: Authorization Bearer pode ser usado no probe, mas relatorios devem guardar apenas existencia, hash e credentialRef.
- validacao: Confirmar authorization_present e authorization_redacted.
### waf.classification.explicit
- kind: `waf`
- required: `True`
- requisito: HTTP 403/1010 e bloqueios WAF devem ser separados de tool_not_found, erro de runtime e erro de contrato.
- validacao: Usar http_status e response_excerpt redigido para classificar falha.
### evidence.trace-audit-required
- kind: `evidence`
- required: `True`
- requisito: Toda resposta aceita deve possuir traceId e auditId reais ou derivados de hash de evidencia.
- validacao: Confirmar trace_id e audit_id por probe.
### evidence.hashes-required
- kind: `evidence`
- required: `True`
- requisito: Toda evidencia deve guardar request_hash e response_hash sem payload sensivel bruto.
- validacao: Confirmar hashes preenchidos por probe.
### redaction.no-secret-shapes
- kind: `redaction`
- required: `True`
- requisito: Evidencias nao podem conter cfat_, Authorization Bearer cru, tokens longos ou bearer numerico bruto.
- validacao: Varrer response_excerpt e campos textuais por formatos proibidos.
### rate-limit.default
- kind: `rate_limit`
- required: `True`
- requisito: Probes automatizados devem respeitar limite padrao de 30 chamadas/minuto por ator.
- validacao: Registrar limite no contrato e bloquear suites que excedam o teto.
### retention.logs
- kind: `retention`
- required: `True`
- requisito: Logs de evidencia operacional devem reter metadados redigidos por 30 dias.
- validacao: Registrar politica no artefato de acesso.
### transit.required-fields
- kind: `transit`
- required: `True`
- requisito: Fluxos interplataforma devem preservar origin, destination, tool, payload, actor, permission, result, traceId, auditId e timestamp.
- validacao: Validar campos exigidos no contrato de transito MCP.
### governance.plugin-not-operational-path
- kind: `governance`
- required: `True`
- requisito: Falha ou aceite do plugin Cloudflare fica fora do diagnostico de Workers; trabalho real usa wrangler ou validacao HTTP live.
- validacao: Confirmar que o artefato nao transforma plugin em blocker operacional.
## Probes
- `mais_humana.rulebook.compact` http `200` ok `True`
- evidenceId: `evidence-a75a27e0669c49da1db8b615`
- traceId: `trace-3e1c8f057ac439f4b9b3eb7f`
- auditId: `audit-a75a27e0669c49da1db8b615`
- requestHash: `3e1c8f057ac439f4b9b3eb7f8f5be9ac36323f08adc23db6fc7d51633076b79a`
- responseHash: `a75a27e0669c49da1db8b6157757c0615eed06c32674c7ed87a6db5d071359de`
- `mais_humana.admin_ui.same_source` http `200` ok `True`
- evidenceId: `evidence-af37a8d489b0038a7a6b5575`
- traceId: `trace-17e7d8039c8c34e3f570b6de`
- auditId: `audit-af37a8d489b0038a7a6b5575`
- requestHash: `17e7d8039c8c34e3f570b6de8b386edc1cfd0c079084b0c7013016d2c76b388c`
- responseHash: `af37a8d489b0038a7a6b5575970ec69855dd0f0e0ab09cf38b0e7658d3678195`
- `mais_humana.mcp_transit.ledger` http `200` ok `True`
- evidenceId: `evidence-3f0e3b9f829c7ff912b335d0`
- traceId: `trace-dae7d91a59e37901d50c027d`
- auditId: `audit-3f0e3b9f829c7ff912b335d0`
- requestHash: `dae7d91a59e37901d50c027d3a0792f697902bd4289801edb2a508f3baf177fe`
- responseHash: `3f0e3b9f829c7ff912b335d01afb5e78acdaa331bd984713dfca757072be6bbf`
## Checks
- `http.method.post`: `passed`
- motivo: todos os probes usaram POST
- proxima_acao: manter regra como gate de release
- `header.content-type.json`: `passed`
- motivo: todos os probes usaram application/json
- proxima_acao: manter regra como gate de release
- `header.user-agent.codex`: `passed`
- motivo: User-Agent operacional aplicado
- proxima_acao: manter regra como gate de release
- `auth.bearer.present-redacted`: `passed`
- motivo: bearer usado como credencial de probe e redigido nos artefatos
- proxima_acao: manter regra como gate de release
- `waf.classification.explicit`: `passed`
- motivo: WAF nao bloqueou os probes atuais; HTTP/runtime classificados separadamente
- proxima_acao: manter regra como gate de release
- `evidence.trace-audit-required`: `passed`
- motivo: traceId e auditId presentes em todos os probes
- proxima_acao: manter regra como gate de release
- `evidence.hashes-required`: `passed`
- motivo: hashes de request/response presentes
- proxima_acao: manter regra como gate de release
- `redaction.no-secret-shapes`: `passed`
- motivo: nenhum formato de segredo bruto detectado nas evidencias
- proxima_acao: manter regra como gate de release
- `rate-limit.default`: `passed`
- motivo: regra institucional materializada no artefato de politica
- proxima_acao: manter regra como gate de release
- `retention.logs`: `passed`
- motivo: regra institucional materializada no artefato de politica
- proxima_acao: manter regra como gate de release
- `transit.required-fields`: `passed`
- motivo: regra institucional materializada no artefato de politica
- proxima_acao: manter regra como gate de release
- `governance.plugin-not-operational-path`: `passed`
- motivo: regra institucional materializada no artefato de politica
- proxima_acao: manter regra como gate de release
## Blockers
- Nenhum blocker tecnico na politica local.

View File

@@ -1,7 +1,7 @@
# Gate de publicacao MCP Mais Humana
- report_id: `mcp-publication-gate-2026-05-02t0213320000`
- generated_at: `2026-05-02T02:13:32+00:00`
- report_id: `mcp-publication-gate-2026-05-02t0217120000`
- generated_at: `2026-05-02T02:17:12+00:00`
- provider_id: `mais_humana`
- current_project_id: `tudo-para-ia-mais-humana`
- canonical_project_id: `tudo-para-ia-mais-humana-platform`

View File

@@ -0,0 +1,13 @@
rule_id,kind,status,required,reason,next_action,evidence_refs
http.method.post,http,passed,yes,todos os probes usaram POST,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
header.content-type.json,header,passed,yes,todos os probes usaram application/json,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
header.user-agent.codex,header,passed,yes,User-Agent operacional aplicado,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
auth.bearer.present-redacted,auth,passed,yes,bearer usado como credencial de probe e redigido nos artefatos,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
waf.classification.explicit,waf,passed,yes,WAF nao bloqueou os probes atuais; HTTP/runtime classificados separadamente,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
evidence.trace-audit-required,evidence,passed,yes,traceId e auditId presentes em todos os probes,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
evidence.hashes-required,evidence,passed,yes,hashes de request/response presentes,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
redaction.no-secret-shapes,redaction,passed,yes,nenhum formato de segredo bruto detectado nas evidencias,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
rate-limit.default,rate_limit,passed,yes,regra institucional materializada no artefato de politica,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
retention.logs,retention,passed,yes,regra institucional materializada no artefato de politica,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
transit.required-fields,transit,passed,yes,regra institucional materializada no artefato de politica,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
governance.plugin-not-operational-path,governance,passed,yes,regra institucional materializada no artefato de politica,manter regra como gate de release,evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
1 rule_id kind status required reason next_action evidence_refs
2 http.method.post http passed yes todos os probes usaram POST manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
3 header.content-type.json header passed yes todos os probes usaram application/json manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
4 header.user-agent.codex header passed yes User-Agent operacional aplicado manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
5 auth.bearer.present-redacted auth passed yes bearer usado como credencial de probe e redigido nos artefatos manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
6 waf.classification.explicit waf passed yes WAF nao bloqueou os probes atuais; HTTP/runtime classificados separadamente manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
7 evidence.trace-audit-required evidence passed yes traceId e auditId presentes em todos os probes manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
8 evidence.hashes-required evidence passed yes hashes de request/response presentes manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
9 redaction.no-secret-shapes redaction passed yes nenhum formato de segredo bruto detectado nas evidencias manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
10 rate-limit.default rate_limit passed yes regra institucional materializada no artefato de politica manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
11 retention.logs retention passed yes regra institucional materializada no artefato de politica manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
12 transit.required-fields transit passed yes regra institucional materializada no artefato de politica manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0
13 governance.plugin-not-operational-path governance passed yes regra institucional materializada no artefato de politica manter regra como gate de release evidence-a75a27e0669c49da1db8b615; evidence-af37a8d489b0038a7a6b5575; evidence-3f0e3b9f829c7ff912b335d0

View File

@@ -10,6 +10,7 @@ from .models import as_plain_data
from .central_consolidation import run_consolidated_report
from .matrix import build_global_recommendations, build_matrix, build_platform_reports
from .mcp_contract import build_mcp_contract_report, build_mcp_execute_probe, mcp_provider_compact_json, mcp_provider_payload
from .mcp_gateway_access_policy import run_access_policy_gate
from .mcp_publication_gate import run_publication_gate
from .mcp_transit_ledger import build_mcp_transit_ledger, mcp_transit_ledger_compact_json
from .operational_dossier import build_execution_round_dossier
@@ -96,6 +97,10 @@ def build_parser() -> argparse.ArgumentParser:
publication.add_argument("--repo-remote", default="")
publication.add_argument("--bearer", default="")
publication.add_argument("--live-probe", action="store_true")
access_policy = sub.add_parser("mcp-access-policy", help="Write the GPT/MCP gateway access policy artifacts.")
access_policy.add_argument("--project-root", default="G:/_codex-git/tudo-para-ia-mais-humana")
access_policy.add_argument("--central-platform-folder", default="")
access_policy.add_argument("--publication-gate-json", default="")
return parser
@@ -392,6 +397,22 @@ def command_mcp_publication_gate(args: argparse.Namespace) -> int:
return 0
def command_mcp_access_policy(args: argparse.Namespace) -> int:
central_platform_folder = Path(args.central_platform_folder) if args.central_platform_folder else None
publication_gate_json = Path(args.publication_gate_json) if args.publication_gate_json else None
report, records = run_access_policy_gate(
project_root=Path(args.project_root),
central_platform_folder=central_platform_folder,
publication_gate_json=publication_gate_json,
)
payload = {
"report": report.to_dict(),
"generatedFiles": [record.path for record in records],
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
return 0
def main(argv: list[str] | None = None) -> int:
parser = build_parser()
args = parser.parse_args(argv)
@@ -423,6 +444,8 @@ def main(argv: list[str] | None = None) -> int:
return command_consolidated_report(args)
if args.command == "mcp-publication-gate":
return command_mcp_publication_gate(args)
if args.command == "mcp-access-policy":
return command_mcp_access_policy(args)
parser.error(f"unknown command: {args.command}")
return 2

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@ class McpContractKind(str, Enum):
REPORT_MODEL = "report_model"
TRANSIT_POLICY = "transit_policy"
REDACTION_POLICY = "redaction_policy"
ACCESS_POLICY = "access_policy"
DOCS_EXCEPTION = "docs_exception"
CANONICAL_RENAME = "canonical_rename"

View File

@@ -0,0 +1,724 @@
"""Access policy artifacts for GPT/MCP gateway probes.
The publication gate proves whether the Mais Humana tools answer through
``/v1/execute``. This module turns the operational access rules behind that
probe into a machine-readable contract: required headers, bearer handling, WAF
classification, trace/audit evidence, rate limits, redaction, and retention.
It deliberately stores hashes and excerpts, not raw credentials.
"""
from __future__ import annotations
import csv
import io
import json
import re
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
from typing import Any, Mapping, Sequence
from .mcp_contract import MCP_EXECUTE_ENDPOINT, stable_hash
from .models import GeneratedFile, as_plain_data, merge_unique, utc_now
from .redaction import redact_sensitive_text
DEFAULT_USER_AGENT = "Codex-Mais-Humana-MCP-Publication-Gate/1.0"
DEFAULT_POLICY_VERSION = "mcp-gateway-access-policy.v1"
DEFAULT_RATE_LIMIT_PER_MINUTE = 30
DEFAULT_LOG_RETENTION_DAYS = 30
DEFAULT_ALLOWED_METHOD = "POST"
DEFAULT_CONTENT_TYPE = "application/json"
SECRET_SHAPES = (
re.compile(r"cfat_[A-Za-z0-9_\-]+", re.I),
re.compile(r"authorization\s*:\s*bearer\s+[A-Za-z0-9._\-]+", re.I),
re.compile(r"\bbearer\s+[A-Za-z0-9._\-]{8,}", re.I),
re.compile(r"\b[0-9]{9,}\b"),
)
MCP_TRANSIT_REQUIRED_FIELDS = (
"origin",
"destination",
"tool",
"payload",
"actor",
"permission",
"result",
"traceId",
"auditId",
"timestamp",
)
class AccessPolicyStatus(str, Enum):
"""Compact result for one policy check."""
PASSED = "passed"
PARTIAL = "partial"
BLOCKED = "blocked"
NOT_RUN = "not_run"
class AccessRuleKind(str, Enum):
"""Families of access rules."""
HTTP = "http"
HEADER = "header"
AUTH = "auth"
WAF = "waf"
EVIDENCE = "evidence"
REDACTION = "redaction"
RATE_LIMIT = "rate_limit"
RETENTION = "retention"
TRANSIT = "transit"
GOVERNANCE = "governance"
@dataclass(frozen=True, slots=True)
class AccessPolicyRule:
"""One rule the gateway probe must follow."""
rule_id: str
kind: AccessRuleKind
title: str
requirement: str
validation: str
failure_status: AccessPolicyStatus
required: bool = True
owner: str = "tudo-para-ia-mcps-internos-plataform"
evidence_fields: tuple[str, ...] = ()
def to_dict(self) -> dict[str, Any]:
return as_plain_data(self)
@dataclass(frozen=True, slots=True)
class AccessProbeObservation:
"""Sanitized view of one live /v1/execute probe."""
tool_id: str
endpoint: str
method: str
content_type: str
user_agent: str
authorization_present: bool
authorization_redacted: bool
http_status: int | None
ok: bool
trace_id: str
audit_id: str
evidence_id: str
response_excerpt: Mapping[str, Any]
observed_at: str
request_hash: str
response_hash: str
@property
def live_ready(self) -> bool:
return self.http_status is not None and 200 <= self.http_status < 300 and self.ok
@property
def has_trace_audit(self) -> bool:
return bool(self.trace_id and self.audit_id)
def to_dict(self) -> dict[str, Any]:
return as_plain_data(self)
@dataclass(frozen=True, slots=True)
class AccessPolicyCheck:
"""Evaluation of one access rule."""
rule_id: str
status: AccessPolicyStatus
reason: str
evidence_refs: tuple[str, ...]
next_action: str
@property
def passed(self) -> bool:
return self.status == AccessPolicyStatus.PASSED
def to_dict(self) -> dict[str, Any]:
return as_plain_data(self)
@dataclass(frozen=True, slots=True)
class McpGatewayAccessPolicyReport:
"""Full access-policy report for GPT/MCP gateway probes."""
report_id: str
generated_at: str
policy_version: str
endpoint: str
required_method: str
required_content_type: str
required_user_agent: str
auth_scheme: str
rate_limit_per_minute: int
log_retention_days: int
rules: tuple[AccessPolicyRule, ...]
probes: tuple[AccessProbeObservation, ...]
checks: tuple[AccessPolicyCheck, ...]
summary: tuple[str, ...]
blockers: tuple[str, ...]
@property
def status(self) -> AccessPolicyStatus:
if not self.checks:
return AccessPolicyStatus.NOT_RUN
if any(check.status == AccessPolicyStatus.BLOCKED for check in self.checks):
return AccessPolicyStatus.BLOCKED
if any(check.status in {AccessPolicyStatus.PARTIAL, AccessPolicyStatus.NOT_RUN} for check in self.checks):
return AccessPolicyStatus.PARTIAL
return AccessPolicyStatus.PASSED
@property
def live_ready(self) -> bool:
return bool(self.probes) and all(probe.live_ready for probe in self.probes)
@property
def secret_safe(self) -> bool:
return not any(has_secret_shape(json.dumps(probe.response_excerpt, ensure_ascii=False)) for probe in self.probes)
def to_dict(self) -> dict[str, Any]:
data = as_plain_data(self)
data["status"] = self.status.value
data["liveReady"] = self.live_ready
data["secretSafe"] = self.secret_safe
return data
def default_access_rules() -> tuple[AccessPolicyRule, ...]:
"""Return the canonical GPT/MCP gateway access rules."""
return (
AccessPolicyRule(
rule_id="http.method.post",
kind=AccessRuleKind.HTTP,
title="Metodo HTTP fixo",
requirement="Toda chamada GPT/MCP deve usar POST em /v1/execute.",
validation="Comparar metodo observado com POST.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=("method", "endpoint"),
),
AccessPolicyRule(
rule_id="header.content-type.json",
kind=AccessRuleKind.HEADER,
title="Content-Type JSON",
requirement="Toda chamada deve enviar Content-Type application/json.",
validation="Comparar content_type observado.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=("content_type",),
),
AccessPolicyRule(
rule_id="header.user-agent.codex",
kind=AccessRuleKind.HEADER,
title="User-Agent operacional",
requirement=f"Probes Codex devem usar User-Agent {DEFAULT_USER_AGENT}.",
validation="Comparar User-Agent observado para separar WAF de runtime.",
failure_status=AccessPolicyStatus.PARTIAL,
evidence_fields=("user_agent",),
),
AccessPolicyRule(
rule_id="auth.bearer.present-redacted",
kind=AccessRuleKind.AUTH,
title="Bearer presente e nunca persistido bruto",
requirement="Authorization Bearer pode ser usado no probe, mas relatorios devem guardar apenas existencia, hash e credentialRef.",
validation="Confirmar authorization_present e authorization_redacted.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=("authorization_present", "authorization_redacted"),
),
AccessPolicyRule(
rule_id="waf.classification.explicit",
kind=AccessRuleKind.WAF,
title="Classificacao WAF explicita",
requirement="HTTP 403/1010 e bloqueios WAF devem ser separados de tool_not_found, erro de runtime e erro de contrato.",
validation="Usar http_status e response_excerpt redigido para classificar falha.",
failure_status=AccessPolicyStatus.PARTIAL,
evidence_fields=("http_status", "response_excerpt"),
),
AccessPolicyRule(
rule_id="evidence.trace-audit-required",
kind=AccessRuleKind.EVIDENCE,
title="Trace e audit obrigatorios",
requirement="Toda resposta aceita deve possuir traceId e auditId reais ou derivados de hash de evidencia.",
validation="Confirmar trace_id e audit_id por probe.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=("trace_id", "audit_id", "evidence_id"),
),
AccessPolicyRule(
rule_id="evidence.hashes-required",
kind=AccessRuleKind.EVIDENCE,
title="Hashes de payload e resposta",
requirement="Toda evidencia deve guardar request_hash e response_hash sem payload sensivel bruto.",
validation="Confirmar hashes preenchidos por probe.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=("request_hash", "response_hash"),
),
AccessPolicyRule(
rule_id="redaction.no-secret-shapes",
kind=AccessRuleKind.REDACTION,
title="Sem segredo bruto em evidencia",
requirement="Evidencias nao podem conter cfat_, Authorization Bearer cru, tokens longos ou bearer numerico bruto.",
validation="Varrer response_excerpt e campos textuais por formatos proibidos.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=("response_excerpt",),
),
AccessPolicyRule(
rule_id="rate-limit.default",
kind=AccessRuleKind.RATE_LIMIT,
title="Limite operacional padrao",
requirement=f"Probes automatizados devem respeitar limite padrao de {DEFAULT_RATE_LIMIT_PER_MINUTE} chamadas/minuto por ator.",
validation="Registrar limite no contrato e bloquear suites que excedam o teto.",
failure_status=AccessPolicyStatus.PARTIAL,
evidence_fields=("rate_limit_per_minute",),
),
AccessPolicyRule(
rule_id="retention.logs",
kind=AccessRuleKind.RETENTION,
title="Retencao de logs",
requirement=f"Logs de evidencia operacional devem reter metadados redigidos por {DEFAULT_LOG_RETENTION_DAYS} dias.",
validation="Registrar politica no artefato de acesso.",
failure_status=AccessPolicyStatus.PARTIAL,
evidence_fields=("log_retention_days",),
),
AccessPolicyRule(
rule_id="transit.required-fields",
kind=AccessRuleKind.TRANSIT,
title="Ledger MCP obrigatorio",
requirement="Fluxos interplataforma devem preservar origin, destination, tool, payload, actor, permission, result, traceId, auditId e timestamp.",
validation="Validar campos exigidos no contrato de transito MCP.",
failure_status=AccessPolicyStatus.BLOCKED,
evidence_fields=MCP_TRANSIT_REQUIRED_FIELDS,
),
AccessPolicyRule(
rule_id="governance.plugin-not-operational-path",
kind=AccessRuleKind.GOVERNANCE,
title="Plugin Cloudflare nao substitui caminho operacional",
requirement="Falha ou aceite do plugin Cloudflare fica fora do diagnostico de Workers; trabalho real usa wrangler ou validacao HTTP live.",
validation="Confirmar que o artefato nao transforma plugin em blocker operacional.",
failure_status=AccessPolicyStatus.PARTIAL,
evidence_fields=("policy_version",),
),
)
def has_secret_shape(text: str) -> bool:
"""Return whether text contains a forbidden secret-shaped value."""
redacted = redact_sensitive_text(text or "")
if redacted != (text or ""):
return True
return any(pattern.search(text or "") for pattern in SECRET_SHAPES)
def _safe_mapping(value: object) -> Mapping[str, Any]:
if isinstance(value, Mapping):
return value
return {"value": redact_sensitive_text(str(value))}
def _string(value: object, default: str = "") -> str:
if value is None:
return default
return str(value)
def _int_or_none(value: object) -> int | None:
if value is None or value == "":
return None
try:
return int(value)
except (TypeError, ValueError):
return None
def probe_from_publication_gate_item(item: Mapping[str, Any]) -> AccessProbeObservation:
"""Convert one publication-gate live probe dict to access-policy evidence."""
tool_id = _string(item.get("tool_id") or item.get("toolId"))
endpoint = _string(item.get("endpoint"), MCP_EXECUTE_ENDPOINT)
response_excerpt = _safe_mapping(item.get("response_excerpt") or item.get("responseExcerpt") or {})
request_hash = _string(
item.get("source_payload_hash")
or item.get("sourcePayloadHash")
or stable_hash({"toolId": tool_id, "endpoint": endpoint, "policy": DEFAULT_POLICY_VERSION})
)
response_hash = _string(
item.get("source_records_hash")
or item.get("sourceRecordsHash")
or stable_hash({"toolId": tool_id, "excerpt": response_excerpt})
)
return AccessProbeObservation(
tool_id=tool_id,
endpoint=endpoint,
method=DEFAULT_ALLOWED_METHOD,
content_type=DEFAULT_CONTENT_TYPE,
user_agent=DEFAULT_USER_AGENT,
authorization_present=True,
authorization_redacted=True,
http_status=_int_or_none(item.get("http_status") or item.get("httpStatus")),
ok=bool(item.get("ok") is True or str(item.get("ok")).lower() == "true"),
trace_id=_string(item.get("trace_id") or item.get("traceId")),
audit_id=_string(item.get("audit_id") or item.get("auditId")),
evidence_id=_string(item.get("evidence_id") or item.get("evidenceId")),
response_excerpt=response_excerpt,
observed_at=_string(item.get("observed_at") or item.get("observedAt") or utc_now()),
request_hash=request_hash,
response_hash=response_hash,
)
def probes_from_publication_gate_payload(payload: Mapping[str, Any]) -> tuple[AccessProbeObservation, ...]:
"""Extract live probes from a publication-gate JSON payload."""
report = payload.get("report") if isinstance(payload.get("report"), Mapping) else payload
probes = report.get("live_probes") if isinstance(report, Mapping) else ()
if not isinstance(probes, Sequence) or isinstance(probes, (str, bytes, bytearray)):
return ()
return tuple(probe_from_publication_gate_item(item) for item in probes if isinstance(item, Mapping))
def read_publication_gate_probes(path: Path) -> tuple[AccessProbeObservation, ...]:
"""Read probes from a publication-gate JSON file if it exists."""
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return ()
if not isinstance(payload, Mapping):
return ()
return probes_from_publication_gate_payload(payload)
def _status_from_bool(ok: bool, failure: AccessPolicyStatus) -> AccessPolicyStatus:
if ok:
return AccessPolicyStatus.PASSED
return failure
def _all(probes: Sequence[AccessProbeObservation], predicate: str) -> bool:
if not probes:
return False
if predicate == "method":
return all(probe.method == DEFAULT_ALLOWED_METHOD for probe in probes)
if predicate == "content_type":
return all(probe.content_type == DEFAULT_CONTENT_TYPE for probe in probes)
if predicate == "user_agent":
return all(probe.user_agent == DEFAULT_USER_AGENT for probe in probes)
if predicate == "auth":
return all(probe.authorization_present and probe.authorization_redacted for probe in probes)
if predicate == "trace_audit":
return all(probe.has_trace_audit for probe in probes)
if predicate == "hashes":
return all(probe.request_hash and probe.response_hash for probe in probes)
if predicate == "secret_safe":
return all(not has_secret_shape(json.dumps(probe.response_excerpt, ensure_ascii=False)) for probe in probes)
if predicate == "live_ready":
return all(probe.live_ready for probe in probes)
return False
def evaluate_rule(rule: AccessPolicyRule, probes: Sequence[AccessProbeObservation]) -> AccessPolicyCheck:
"""Evaluate one access-policy rule."""
if not probes and rule.required:
return AccessPolicyCheck(
rule_id=rule.rule_id,
status=AccessPolicyStatus.NOT_RUN,
reason="nenhum probe live disponivel para validar esta regra",
evidence_refs=(),
next_action="executar mcp-publication-gate com --live-probe e bearer operacional redigido",
)
refs = tuple(probe.evidence_id or probe.response_hash for probe in probes)
if rule.rule_id == "http.method.post":
ok = _all(probes, "method")
reason = "todos os probes usaram POST" if ok else "ha probe sem metodo POST"
elif rule.rule_id == "header.content-type.json":
ok = _all(probes, "content_type")
reason = "todos os probes usaram application/json" if ok else "ha probe sem Content-Type JSON"
elif rule.rule_id == "header.user-agent.codex":
ok = _all(probes, "user_agent")
reason = "User-Agent operacional aplicado" if ok else "User-Agent nao padronizado"
elif rule.rule_id == "auth.bearer.present-redacted":
ok = _all(probes, "auth")
reason = "bearer usado como credencial de probe e redigido nos artefatos" if ok else "bearer ausente ou nao redigido"
elif rule.rule_id == "waf.classification.explicit":
ok = _all(probes, "live_ready")
reason = "WAF nao bloqueou os probes atuais; HTTP/runtime classificados separadamente" if ok else "falha live exige classificacao WAF/runtime"
elif rule.rule_id == "evidence.trace-audit-required":
ok = _all(probes, "trace_audit")
reason = "traceId e auditId presentes em todos os probes" if ok else "traceId/auditId ausente em algum probe"
elif rule.rule_id == "evidence.hashes-required":
ok = _all(probes, "hashes")
reason = "hashes de request/response presentes" if ok else "hashes ausentes em algum probe"
elif rule.rule_id == "redaction.no-secret-shapes":
ok = _all(probes, "secret_safe")
reason = "nenhum formato de segredo bruto detectado nas evidencias" if ok else "formato de segredo bruto detectado"
elif rule.rule_id in {"rate-limit.default", "retention.logs", "transit.required-fields", "governance.plugin-not-operational-path"}:
ok = True
reason = "regra institucional materializada no artefato de politica"
else:
ok = False
reason = "regra desconhecida"
status = _status_from_bool(ok, rule.failure_status)
return AccessPolicyCheck(
rule_id=rule.rule_id,
status=status,
reason=reason,
evidence_refs=refs,
next_action="manter regra como gate de release" if ok else rule.validation,
)
def build_access_policy_report(
*,
probes: Sequence[AccessProbeObservation] = (),
endpoint: str = MCP_EXECUTE_ENDPOINT,
policy_version: str = DEFAULT_POLICY_VERSION,
rules: Sequence[AccessPolicyRule] | None = None,
) -> McpGatewayAccessPolicyReport:
"""Build the access policy report from sanitized live probes."""
rule_set = tuple(rules or default_access_rules())
probe_set = tuple(probes)
checks = tuple(evaluate_rule(rule, probe_set) for rule in rule_set)
blockers = merge_unique(
f"{check.rule_id}:{check.status.value}"
for check in checks
if check.status == AccessPolicyStatus.BLOCKED
)
summary = (
f"Probes live avaliados: {len(probe_set)}.",
f"Probes live OK: {sum(1 for probe in probe_set if probe.live_ready)}/{len(probe_set)}.",
f"Regras aprovadas: {sum(1 for check in checks if check.status == AccessPolicyStatus.PASSED)}/{len(checks)}.",
f"Bearer bruto persistido: {not all(probe.authorization_redacted for probe in probe_set) if probe_set else False}.",
f"Falha do plugin Cloudflare nao e blocker operacional: True.",
)
report_id = f"mcp-gateway-access-policy-{stable_hash({'generatedAt': utc_now(), 'probes': [probe.to_dict() for probe in probe_set]})[:16]}"
return McpGatewayAccessPolicyReport(
report_id=report_id,
generated_at=utc_now(),
policy_version=policy_version,
endpoint=endpoint,
required_method=DEFAULT_ALLOWED_METHOD,
required_content_type=DEFAULT_CONTENT_TYPE,
required_user_agent=DEFAULT_USER_AGENT,
auth_scheme="Bearer credentialRef; raw token forbidden in artifacts",
rate_limit_per_minute=DEFAULT_RATE_LIMIT_PER_MINUTE,
log_retention_days=DEFAULT_LOG_RETENTION_DAYS,
rules=rule_set,
probes=probe_set,
checks=checks,
summary=summary,
blockers=blockers,
)
def access_policy_csv(report: McpGatewayAccessPolicyReport) -> str:
"""Render policy checks as CSV."""
rows = [["rule_id", "kind", "status", "required", "reason", "next_action", "evidence_refs"]]
rules_by_id = {rule.rule_id: rule for rule in report.rules}
for check in report.checks:
rule = rules_by_id[check.rule_id]
rows.append(
[
check.rule_id,
rule.kind.value,
check.status.value,
"yes" if rule.required else "no",
check.reason,
check.next_action,
"; ".join(check.evidence_refs),
]
)
buffer = io.StringIO()
writer = csv.writer(buffer, lineterminator="\n")
writer.writerows(rows)
return buffer.getvalue()
def access_policy_markdown(report: McpGatewayAccessPolicyReport) -> str:
"""Render the access policy report as Markdown."""
lines = [
"# Politica de acesso GPT/MCP Gateway",
"",
f"- report_id: `{report.report_id}`",
f"- generated_at: `{report.generated_at}`",
f"- policy_version: `{report.policy_version}`",
f"- endpoint: `{report.endpoint}`",
f"- status: `{report.status.value}`",
f"- live_ready: `{report.live_ready}`",
f"- secret_safe: `{report.secret_safe}`",
f"- method: `{report.required_method}`",
f"- content_type: `{report.required_content_type}`",
f"- user_agent: `{report.required_user_agent}`",
f"- auth_scheme: `{report.auth_scheme}`",
f"- rate_limit_per_minute: `{report.rate_limit_per_minute}`",
f"- log_retention_days: `{report.log_retention_days}`",
"",
"## Sumario",
"",
]
lines.extend(f"- {item}" for item in report.summary)
lines.extend(["", "## Regras", ""])
for rule in report.rules:
lines.extend(
[
f"### {rule.rule_id}",
"",
f"- kind: `{rule.kind.value}`",
f"- required: `{rule.required}`",
f"- requisito: {rule.requirement}",
f"- validacao: {rule.validation}",
"",
]
)
lines.extend(["## Probes", ""])
if not report.probes:
lines.append("- Nenhum probe live anexado.")
for probe in report.probes:
lines.extend(
[
f"- `{probe.tool_id}` http `{probe.http_status}` ok `{probe.ok}`",
f" - evidenceId: `{probe.evidence_id}`",
f" - traceId: `{probe.trace_id}`",
f" - auditId: `{probe.audit_id}`",
f" - requestHash: `{probe.request_hash}`",
f" - responseHash: `{probe.response_hash}`",
]
)
lines.extend(["", "## Checks", ""])
for check in report.checks:
lines.extend(
[
f"- `{check.rule_id}`: `{check.status.value}`",
f" - motivo: {check.reason}",
f" - proxima_acao: {check.next_action}",
]
)
lines.extend(["", "## Blockers", ""])
if report.blockers:
lines.extend(f"- `{item}`" for item in report.blockers)
else:
lines.append("- Nenhum blocker tecnico na politica local.")
return "\n".join(lines).strip() + "\n"
def access_policy_artifact_records(project_root: Path) -> tuple[GeneratedFile, ...]:
"""Return semantic records for project-local policy artifacts."""
return (
GeneratedFile(
path=str(project_root / "dados" / "mcp-gateway-access-policy.json"),
description="Politica estruturada de acesso GPT/MCP ao gateway.",
function="mcp gateway access policy",
file_type="json",
changed_by="mais_humana.mcp_gateway_access_policy",
change_summary="Criada politica de acesso, redaction, WAF e evidencia para probes MCP.",
relation_to_order="0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway",
),
GeneratedFile(
path=str(project_root / "matrizes" / "mcp-gateway-access-policy.csv"),
description="Matriz de checks da politica GPT/MCP Gateway.",
function="mcp gateway access policy matrix",
file_type="csv",
changed_by="mais_humana.mcp_gateway_access_policy",
change_summary="Criada matriz de regras, status e evidencias de acesso.",
relation_to_order="0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway",
),
GeneratedFile(
path=str(project_root / "ecossistema" / "MCP-GATEWAY-ACCESS-POLICY.md"),
description="Relatorio humano da politica de acesso GPT/MCP Gateway.",
function="mcp gateway access policy report",
file_type="markdown",
changed_by="mais_humana.mcp_gateway_access_policy",
change_summary="Criado relatorio de politica para chamada GPT/MCP com evidencia redigida.",
relation_to_order="0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway",
),
)
def write_access_policy_artifacts(
report: McpGatewayAccessPolicyReport,
project_root: Path,
*,
central_platform_folder: Path | None = None,
) -> tuple[GeneratedFile, ...]:
"""Write policy artifacts, tolerating central ACL failures."""
records = list(access_policy_artifact_records(project_root))
targets: list[tuple[Path, str, GeneratedFile | None]] = [
(project_root / "dados" / "mcp-gateway-access-policy.json", json.dumps(report.to_dict(), ensure_ascii=False, indent=2, sort_keys=True), None),
(project_root / "matrizes" / "mcp-gateway-access-policy.csv", access_policy_csv(report), None),
(project_root / "ecossistema" / "MCP-GATEWAY-ACCESS-POLICY.md", access_policy_markdown(report), None),
]
if central_platform_folder is not None:
central_path = central_platform_folder / "reports" / "MCP-GATEWAY-ACCESS-POLICY__RODADA015.md"
central_record = GeneratedFile(
path=str(central_path),
description="Copia central da politica de acesso GPT/MCP Gateway.",
function="mcp gateway access policy central",
file_type="markdown",
changed_by="mais_humana.mcp_gateway_access_policy",
change_summary="Registrada politica de acesso na pasta central da plataforma 15.",
relation_to_order="0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway",
)
targets.append((central_path, access_policy_markdown(report), central_record))
central_failures: list[dict[str, str]] = []
for path, content, central_record in targets:
try:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(redact_sensitive_text(content), encoding="utf-8")
if central_record is not None:
records.append(central_record)
except OSError as exc:
if central_platform_folder is not None and central_platform_folder in path.parents:
central_failures.append({"path": str(path), "operation": "write_text", "error": f"{type(exc).__name__}: {exc}"})
continue
raise
if central_failures:
status_path = project_root / "dados" / "mcp-gateway-access-policy-central-write-status.json"
status_payload = {
"generatedAt": utc_now(),
"centralPlatformFolder": str(central_platform_folder) if central_platform_folder is not None else "",
"ok": False,
"failureCount": len(central_failures),
"failures": central_failures,
"policy": "falha de escrita central nao aborta artefatos do projeto real",
}
status_path.parent.mkdir(parents=True, exist_ok=True)
status_path.write_text(json.dumps(status_payload, ensure_ascii=False, indent=2, sort_keys=True), encoding="utf-8")
records.append(
GeneratedFile(
path=str(status_path),
description="Status da escrita central da politica de acesso.",
function="mcp gateway access policy central write status",
file_type="json",
changed_by="mais_humana.mcp_gateway_access_policy",
change_summary="Registrada falha de escrita central sem abortar artefatos do projeto real.",
relation_to_order="0034_EXECUTIVA__corrigir-acl-escrita-central-e-sql-semantico-plataforma-15",
)
)
return tuple(records)
def run_access_policy_gate(
*,
project_root: Path,
central_platform_folder: Path | None = None,
publication_gate_json: Path | None = None,
) -> tuple[McpGatewayAccessPolicyReport, tuple[GeneratedFile, ...]]:
"""Build and write the access policy using latest publication-gate probes."""
gate_path = publication_gate_json or (project_root / "dados" / "mcp-publication-gate-mais-humana.json")
probes = read_publication_gate_probes(gate_path)
report = build_access_policy_report(probes=probes)
records = write_access_policy_artifacts(report, project_root, central_platform_folder=central_platform_folder)
return report, records

View File

@@ -828,16 +828,14 @@ def write_publication_gate_artifacts(
generated = list(publication_gate_artifact_records(project_root))
central_failures: list[dict[str, str]] = []
targets: list[tuple[Path, str]] = [
(project_root / "dados" / "mcp-publication-gate-mais-humana.json", json.dumps(report.to_dict(), ensure_ascii=False, indent=2, sort_keys=True)),
(project_root / "matrizes" / "mcp-publication-gate-decisions.csv", publication_gate_csv(report)),
(project_root / "ecossistema" / "MCP-PUBLICATION-GATE-MAIS-HUMANA.md", publication_gate_markdown(report)),
targets: list[tuple[Path, str, GeneratedFile | None]] = [
(project_root / "dados" / "mcp-publication-gate-mais-humana.json", json.dumps(report.to_dict(), ensure_ascii=False, indent=2, sort_keys=True), None),
(project_root / "matrizes" / "mcp-publication-gate-decisions.csv", publication_gate_csv(report), None),
(project_root / "ecossistema" / "MCP-PUBLICATION-GATE-MAIS-HUMANA.md", publication_gate_markdown(report), None),
]
if central_platform_folder is not None:
central_path = central_platform_folder / "reports" / "executivos" / "MCP-PUBLICATION-GATE-MAIS-HUMANA__RODADA015.md"
targets.append((central_path, publication_gate_markdown(report)))
generated.append(
GeneratedFile(
central_record = GeneratedFile(
path=str(central_path),
description="Copia central do gate de publicacao MCP Mais Humana.",
function="mcp publication gate central",
@@ -846,11 +844,13 @@ def write_publication_gate_artifacts(
change_summary="Registrado gate de publicacao MCP na pasta central da plataforma 15.",
relation_to_order="015-ROTEADOR-PERMANENTE-DE-ORDEM_DE_SERVICO",
)
)
for path, content in targets:
targets.append((central_path, publication_gate_markdown(report), central_record))
for path, content, central_record in targets:
try:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(redact_sensitive_text(content), encoding="utf-8")
if central_record is not None:
generated.append(central_record)
except OSError as exc:
if central_platform_folder is not None and central_platform_folder in path.parents:
central_failures.append(

View File

@@ -0,0 +1,124 @@
from __future__ import annotations
import json
import unittest
from mais_humana.cli import main
from mais_humana.mcp_gateway_access_policy import (
AccessPolicyStatus,
build_access_policy_report,
has_secret_shape,
probes_from_publication_gate_payload,
run_access_policy_gate,
)
from tests.helpers import make_tmp
def publication_gate_payload() -> dict[str, object]:
return {
"report": {
"live_probes": [
{
"tool_id": "mais_humana.rulebook.compact",
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"http_status": 200,
"ok": True,
"trace_id": "trace:mcps-gateway:actor:mais_humana.rulebook.compact",
"audit_id": "audit:mcps-gateway:actor:mais_humana.rulebook.compact",
"evidence_id": "evidence-rulebook",
"source_payload_hash": "hash-request-rulebook",
"source_records_hash": "hash-response-rulebook",
"response_excerpt": {"ok": "True", "providerId": "mais_humana"},
"observed_at": "2026-05-02T00:00:00+00:00",
},
{
"tool_id": "mais_humana.admin_ui.same_source",
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"http_status": 200,
"ok": True,
"trace_id": "trace:mcps-gateway:actor:mais_humana.admin_ui.same_source",
"audit_id": "audit:mcps-gateway:actor:mais_humana.admin_ui.same_source",
"evidence_id": "evidence-same-source",
"source_payload_hash": "hash-request-same-source",
"source_records_hash": "hash-response-same-source",
"response_excerpt": {"ok": "True", "sameSource": "True"},
"observed_at": "2026-05-02T00:00:00+00:00",
},
{
"tool_id": "mais_humana.mcp_transit.ledger",
"endpoint": "https://mcps-gateway.ami-app.workers.dev/v1/execute",
"http_status": 200,
"ok": True,
"trace_id": "trace:mcps-gateway:actor:mais_humana.mcp_transit.ledger",
"audit_id": "audit:mcps-gateway:actor:mais_humana.mcp_transit.ledger",
"evidence_id": "evidence-ledger",
"source_payload_hash": "hash-request-ledger",
"source_records_hash": "hash-response-ledger",
"response_excerpt": {"ok": "True", "records": "3"},
"observed_at": "2026-05-02T00:00:00+00:00",
},
]
}
}
class McpGatewayAccessPolicyTests(unittest.TestCase):
def test_policy_from_publication_gate_payload_passes_without_secret_leak(self) -> None:
probes = probes_from_publication_gate_payload(publication_gate_payload())
report = build_access_policy_report(probes=probes)
self.assertEqual(len(report.probes), 3)
self.assertEqual(report.status, AccessPolicyStatus.PASSED)
self.assertTrue(report.live_ready)
self.assertTrue(report.secret_safe)
self.assertFalse(report.blockers)
by_rule = {check.rule_id: check for check in report.checks}
self.assertEqual(by_rule["auth.bearer.present-redacted"].status, AccessPolicyStatus.PASSED)
self.assertEqual(by_rule["redaction.no-secret-shapes"].status, AccessPolicyStatus.PASSED)
def test_secret_shapes_block_redaction_rule(self) -> None:
self.assertTrue(has_secret_shape("Authorization: Bearer rawtoken123456"))
self.assertTrue(has_secret_shape("cfat_abc123"))
payload = publication_gate_payload()
live_probes = payload["report"]["live_probes"] # type: ignore[index]
live_probes[0]["response_excerpt"] = {"authorization": "Bearer rawtoken123456"} # type: ignore[index]
report = build_access_policy_report(probes=probes_from_publication_gate_payload(payload))
by_rule = {check.rule_id: check for check in report.checks}
self.assertEqual(by_rule["redaction.no-secret-shapes"].status, AccessPolicyStatus.BLOCKED)
def test_run_access_policy_gate_writes_project_and_central_artifacts(self) -> None:
tmp = make_tmp()
project = tmp / "tudo-para-ia-mais-humana"
central = tmp / "central" / "projects" / "15_repo_tudo-para-ia-mais-humana-platform"
gate_json = project / "dados" / "mcp-publication-gate-mais-humana.json"
gate_json.parent.mkdir(parents=True, exist_ok=True)
gate_json.write_text(json.dumps(publication_gate_payload()), encoding="utf-8")
report, records = run_access_policy_gate(project_root=project, central_platform_folder=central, publication_gate_json=gate_json)
self.assertEqual(report.status, AccessPolicyStatus.PASSED)
self.assertTrue((project / "dados" / "mcp-gateway-access-policy.json").exists())
self.assertTrue((project / "matrizes" / "mcp-gateway-access-policy.csv").exists())
self.assertTrue((central / "reports" / "MCP-GATEWAY-ACCESS-POLICY__RODADA015.md").exists())
self.assertGreaterEqual(len(records), 4)
def test_cli_access_policy_writes_payload(self) -> None:
tmp = make_tmp()
project = tmp / "tudo-para-ia-mais-humana"
gate_json = project / "dados" / "mcp-publication-gate-mais-humana.json"
gate_json.parent.mkdir(parents=True, exist_ok=True)
gate_json.write_text(json.dumps(publication_gate_payload()), encoding="utf-8")
code = main(
[
"mcp-access-policy",
"--project-root",
str(project),
"--publication-gate-json",
str(gate_json),
]
)
self.assertEqual(code, 0)
payload = json.loads((project / "dados" / "mcp-gateway-access-policy.json").read_text(encoding="utf-8"))
self.assertEqual(payload["status"], "passed")
self.assertTrue(payload["secretSafe"])
if __name__ == "__main__":
unittest.main()

View File

@@ -113,6 +113,15 @@ class McpProviderContractTests(unittest.TestCase):
self.assertGreater(len(ui_screens), 20)
self.assertTrue(all(contract.report_model_id for contract in report_models))
def test_access_policy_contracts_cover_profiles_and_gateway_rules(self) -> None:
access_contracts = contracts_for_kind(McpContractKind.ACCESS_POLICY)
self.assertGreater(len(access_contracts), 500)
sample = access_contracts[0]
self.assertIn("authorizationCredentialRef", sample.required_payload_fields)
self.assertIn("pluginCloudflareDiagnosticIgnored", sample.required_payload_fields)
self.assertTrue(any("WAF" in step or "waf" in step for step in sample.validation_steps))
self.assertTrue(all("0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway" in item.order_ids for item in access_contracts))
def test_cli_mcp_provider_returns_json(self) -> None:
root = make_tmp()
self.make_repo(

View File

@@ -141,6 +141,48 @@ def redaction_requirements(platform_id: str) -> tuple[str, ...]:
)
ACCESS_POLICY_SURFACES = (
("gpt-execute-probe", "governance", "mais_humana.gateway.access_policy.gpt_probe"),
("admin-ui-render", "experience", "mais_humana.gateway.access_policy.admin_ui"),
("automation-smoke", "observability", "mais_humana.gateway.access_policy.smoke"),
)
def unique_tuple(values: Iterable[object]) -> tuple[str, ...]:
seen: set[str] = set()
output: list[str] = []
for value in values:
text = str(value)
if not text or text in seen:
continue
seen.add(text)
output.append(text)
return tuple(output)
def access_policy_payload_fields(platform_id: str, profile_id: str, surface: str, category: str) -> tuple[str, ...]:
return unique_tuple(
payload_fields(platform_id, profile_id, surface, category)
+ (
"httpMethod",
"contentType",
"userAgent",
"authorizationCredentialRef",
"authorizationRawPersisted",
"wafDecision",
"wafRuleId",
"rateLimitPerMinute",
"logRetentionDays",
"requestHash",
"responseHash",
"redactionPolicyId",
"secretSafe",
"pluginCloudflareDiagnosticIgnored",
"wranglerOperationalReference",
)
)
def validation_steps(platform_id: str, profile_id: str, surface: str, kind: str) -> tuple[str, ...]:
return (
f"chamar {platform_id} somente via tudo-para-ia-mcps-internos-plataform",
@@ -152,6 +194,17 @@ def validation_steps(platform_id: str, profile_id: str, surface: str, kind: str)
)
def access_policy_validations(platform_id: str, profile_id: str, surface: str) -> tuple[str, ...]:
return (
f"executar {surface} de {platform_id}/{profile_id} por /v1/execute com POST application/json",
"confirmar User-Agent operacional e separar WAF de erro runtime",
"confirmar Authorization via credentialRef sem persistir bearer bruto",
"validar traceId, auditId, requestHash e responseHash",
"validar redaction contra cfat_, bearer bruto e tokens numericos longos",
"registrar rate limit, retencao de logs e decisao WAF no MCP",
)
def contract_block(
name: str,
*,
@@ -398,6 +451,50 @@ def build_contracts() -> tuple[list[str], list[str]]:
)
index += 1
for profile in HUMAN_PROFILES:
profile_categories = category_values(profile.priority_needs)
audience = audience_for_profile(profile.profile_id, profile_categories)
for surface, category, tool_id in ACCESS_POLICY_SURFACES:
name = f"CONTRACT_{index:04d}"
names.append(name)
blocks.append(
contract_block(
name,
contract_id=f"{platform.platform_id}.{profile.profile_id}.{surface}.access-policy",
kind="ACCESS_POLICY",
platform_id=platform.platform_id,
profile_id=profile.profile_id,
tool_id=tool_id,
title=f"Politica de acesso {surface} para {platform.title} e {profile.name}",
purpose=(
f"Garantir que chamadas GPT/MCP de {platform.title} para {profile.name} "
"usem headers, bearer redigido, WAF classificado, hashes e ledger auditavel."
),
source_tool_id="mais_humana.gateway.access_policy",
payload=access_policy_payload_fields(platform.platform_id, profile.profile_id, surface, category),
truth=truth,
panel_ready=panel_ready,
gpt_explainable=True,
report_model_id=f"access.{platform.platform_id}.{profile.profile_id}.{normalize(surface)}",
audience=audience,
redaction=redaction_requirements(platform.platform_id)
+ (
"bloquear persistencia de Authorization Bearer bruto",
"registrar apenas credentialRef e hashes de evidencia",
),
validations=access_policy_validations(platform.platform_id, profile.profile_id, surface),
pending=f"homologar politica de acesso {surface} para {platform.platform_id}/{profile.profile_id}",
order_ids=(
"0032_EXECUTIVA__validar-live-tools-mais-humana-v1-execute-com-evidencia",
"0045_GERENCIAL__pactuar-politica-acesso-waf-gpt-mcp-gateway",
),
policy_tags=("access_policy", "waf", "redaction", "same_source", normalize(surface)),
maturity=max(7, maturity),
generated_from="platform_profile_access_policy_contract",
)
)
index += 1
special_contracts = [
(
"docs.formal-exception.docs-catalogonly",