|
| 1 | +{ |
| 2 | + "$schema": "http://json-schema.org/draft-07/schema#", |
| 3 | + "$id": "https://raw.githubusercontent.com/petrsnd/SafeguardCustomPlatform/main/.agents/schemas/evidence.schema.json", |
| 4 | + "title": "Custom Platform Probing Evidence", |
| 5 | + "description": "Internal agent contract. The evidence artifact produced by the target-probing skill and consumed by strategy-selection and script-authoring. Distinct from the human-facing platform-script schema in schema/. This is v0 — fields marked TODO require a real probing run to lock down their shape; do not invent values.", |
| 6 | + "type": "object", |
| 7 | + "required": [ |
| 8 | + "schemaVersion", |
| 9 | + "protocol", |
| 10 | + "target", |
| 11 | + "serviceAccount", |
| 12 | + "probeRun" |
| 13 | + ], |
| 14 | + "additionalProperties": false, |
| 15 | + "properties": { |
| 16 | + "schemaVersion": { |
| 17 | + "type": "string", |
| 18 | + "description": "Version of this evidence schema. Bumped when the contract changes.", |
| 19 | + "const": "0.1" |
| 20 | + }, |
| 21 | + "protocol": { |
| 22 | + "type": "string", |
| 23 | + "description": "Transport protocol of the target. SSH and HTTP only — telnet is out of scope for the agent skill system.", |
| 24 | + "enum": ["ssh", "http"] |
| 25 | + }, |
| 26 | + "target": { |
| 27 | + "type": "object", |
| 28 | + "description": "Identification of the target system the probes ran against.", |
| 29 | + "required": ["host"], |
| 30 | + "additionalProperties": false, |
| 31 | + "properties": { |
| 32 | + "host": { |
| 33 | + "type": "string", |
| 34 | + "description": "Hostname or IP of the target. No credentials." |
| 35 | + }, |
| 36 | + "port": { |
| 37 | + "type": "integer", |
| 38 | + "description": "TCP port. Optional; default depends on protocol." |
| 39 | + }, |
| 40 | + "nonProductionAffirmed": { |
| 41 | + "type": "boolean", |
| 42 | + "description": "Whether the operator has affirmed the target is non-production. The probe-safety contract requires this to be true before any probe runs." |
| 43 | + } |
| 44 | + } |
| 45 | + }, |
| 46 | + "serviceAccount": { |
| 47 | + "type": "object", |
| 48 | + "description": "Service-account identification used by probes to authenticate to the target. Secrets MUST NOT appear here — name and credential kind only.", |
| 49 | + "required": ["accountName"], |
| 50 | + "additionalProperties": false, |
| 51 | + "properties": { |
| 52 | + "accountName": { |
| 53 | + "type": "string", |
| 54 | + "description": "Username/account identifier used for probing. The secret itself is never recorded in evidence." |
| 55 | + }, |
| 56 | + "credentialKind": { |
| 57 | + "type": "string", |
| 58 | + "description": "What kind of credential the service account uses. Sourced from operator declaration; not inferred.", |
| 59 | + "enum": ["password", "ssh-key", "api-key", "bearer-token", "unknown"] |
| 60 | + } |
| 61 | + } |
| 62 | + }, |
| 63 | + "probeRun": { |
| 64 | + "type": "object", |
| 65 | + "description": "Metadata about the probing session itself.", |
| 66 | + "required": ["startedAt", "probes"], |
| 67 | + "additionalProperties": false, |
| 68 | + "properties": { |
| 69 | + "startedAt": { |
| 70 | + "type": "string", |
| 71 | + "format": "date-time", |
| 72 | + "description": "ISO-8601 UTC timestamp when probing began." |
| 73 | + }, |
| 74 | + "endedAt": { |
| 75 | + "type": "string", |
| 76 | + "format": "date-time", |
| 77 | + "description": "ISO-8601 UTC timestamp when probing concluded. Optional while probing is in progress." |
| 78 | + }, |
| 79 | + "operatorTool": { |
| 80 | + "type": "string", |
| 81 | + "description": "Identifier of the agent runtime that performed the probes (e.g., 'github-copilot-cli', 'claude-code'). For audit only." |
| 82 | + }, |
| 83 | + "probes": { |
| 84 | + "type": "array", |
| 85 | + "description": "Ordered record of probes executed. Each entry is a single probe step. Read-only probes record observations; destructive probes additionally record the explicit per-probe consent given by the operator (see the probe-safety contract in target-probing/SKILL.md).", |
| 86 | + "items": { |
| 87 | + "$ref": "#/definitions/probeRecord" |
| 88 | + } |
| 89 | + }, |
| 90 | + "haltedReason": { |
| 91 | + "type": "string", |
| 92 | + "description": "If probing stopped before completion, why. Examples: 'lockout-signal', 'throttle-signal', 'mfa-challenge', 'operator-stop', 'rate-limit-exceeded'.", |
| 93 | + "enum": [ |
| 94 | + "completed", |
| 95 | + "lockout-signal", |
| 96 | + "throttle-signal", |
| 97 | + "mfa-challenge", |
| 98 | + "operator-stop", |
| 99 | + "rate-limit-exceeded", |
| 100 | + "operator-denied-destructive", |
| 101 | + "error" |
| 102 | + ] |
| 103 | + } |
| 104 | + } |
| 105 | + }, |
| 106 | + "sshFindings": { |
| 107 | + "$ref": "#/definitions/sshFindings", |
| 108 | + "description": "Findings produced by SSH probe playbooks. Present only when protocol == 'ssh'." |
| 109 | + }, |
| 110 | + "httpFindings": { |
| 111 | + "$ref": "#/definitions/httpFindings", |
| 112 | + "description": "Findings produced by HTTP probe playbooks. Present only when protocol == 'http'." |
| 113 | + }, |
| 114 | + "strategyHints": { |
| 115 | + "type": "object", |
| 116 | + "description": "Optional hints from the probing skill that strategy-selection may consider. Not authoritative — strategy-selection makes the final call.", |
| 117 | + "additionalProperties": false, |
| 118 | + "properties": { |
| 119 | + "preferredPattern": { |
| 120 | + "type": "string", |
| 121 | + "description": "If probing strongly suggests one of the four authoring patterns, name it here. Otherwise omit.", |
| 122 | + "enum": [ |
| 123 | + "ssh-interactive", |
| 124 | + "ssh-batch", |
| 125 | + "http-api", |
| 126 | + "http-form-fill" |
| 127 | + ] |
| 128 | + }, |
| 129 | + "rationale": { |
| 130 | + "type": "string", |
| 131 | + "description": "Short, citation-style reason for the hint. Must reference a specific probe record, not be generic." |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + }, |
| 136 | + "definitions": { |
| 137 | + "probeRecord": { |
| 138 | + "type": "object", |
| 139 | + "description": "A single probe step. Field shapes for 'observation' and 'destructiveDetails' are placeholders pending a real probing run; populated structures land in Phase 3 / Phase 5.", |
| 140 | + "required": ["id", "kind", "command", "result"], |
| 141 | + "additionalProperties": false, |
| 142 | + "properties": { |
| 143 | + "id": { |
| 144 | + "type": "string", |
| 145 | + "description": "Stable ID of the probe within this run. Used for back-references." |
| 146 | + }, |
| 147 | + "kind": { |
| 148 | + "type": "string", |
| 149 | + "description": "Probe classification. Read-only probes never mutate target state.", |
| 150 | + "enum": ["read-only", "destructive"] |
| 151 | + }, |
| 152 | + "category": { |
| 153 | + "type": "string", |
| 154 | + "description": "What the probe is investigating. SSH categories: prompt, batch-mode, sudo, password-change. HTTP categories: auth-scheme, login-form, cookie, api-discovery.", |
| 155 | + "enum": [ |
| 156 | + "prompt", |
| 157 | + "batch-mode", |
| 158 | + "sudo", |
| 159 | + "password-change", |
| 160 | + "auth-scheme", |
| 161 | + "login-form", |
| 162 | + "cookie", |
| 163 | + "api-discovery", |
| 164 | + "other" |
| 165 | + ] |
| 166 | + }, |
| 167 | + "command": { |
| 168 | + "type": "string", |
| 169 | + "description": "The exact command or HTTP request line that was issued. No secrets — substitute placeholders for credentials." |
| 170 | + }, |
| 171 | + "consent": { |
| 172 | + "type": "object", |
| 173 | + "description": "Required for destructive probes; absent for read-only probes.", |
| 174 | + "additionalProperties": false, |
| 175 | + "required": ["grantedAt"], |
| 176 | + "properties": { |
| 177 | + "grantedAt": { |
| 178 | + "type": "string", |
| 179 | + "format": "date-time", |
| 180 | + "description": "Timestamp the operator granted explicit per-probe consent." |
| 181 | + }, |
| 182 | + "summaryShown": { |
| 183 | + "type": "string", |
| 184 | + "description": "The one-line 'what this will do, what could go wrong' summary that the operator approved." |
| 185 | + } |
| 186 | + } |
| 187 | + }, |
| 188 | + "result": { |
| 189 | + "type": "string", |
| 190 | + "description": "Outcome of the probe.", |
| 191 | + "enum": ["ok", "failed", "skipped", "halted"] |
| 192 | + }, |
| 193 | + "observation": { |
| 194 | + "description": "TODO: structured observation payload. Shape locked down in Phase 3 once the SSH and HTTP playbooks are authored against real targets. Free-form for now.", |
| 195 | + "type": "object", |
| 196 | + "additionalProperties": true |
| 197 | + }, |
| 198 | + "errorSignature": { |
| 199 | + "type": "string", |
| 200 | + "description": "If result is 'failed', a short stable signature suitable for matching against docs/agent-reference/failure-patterns.md. Optional." |
| 201 | + } |
| 202 | + } |
| 203 | + }, |
| 204 | + "sshFindings": { |
| 205 | + "type": "object", |
| 206 | + "description": "SSH-specific finding shapes. Fields below are the categories the playbook MUST cover; their internal shape is intentionally permissive in v0 and will be tightened once more SSH targets have been probed.", |
| 207 | + "additionalProperties": false, |
| 208 | + "properties": { |
| 209 | + "shellPrompt": { |
| 210 | + "type": "object", |
| 211 | + "additionalProperties": true, |
| 212 | + "description": "What the shell prompt looks like, banner contents, motd presence, etc." |
| 213 | + }, |
| 214 | + "batchModeSupported": { |
| 215 | + "type": "object", |
| 216 | + "additionalProperties": true, |
| 217 | + "description": "Whether non-interactive ExecuteCommand-style probes succeeded vs needed a PTY." |
| 218 | + }, |
| 219 | + "sudoBehavior": { |
| 220 | + "type": "object", |
| 221 | + "additionalProperties": true, |
| 222 | + "description": "Whether sudo prompts for a password, has NOPASSWD, or is not present." |
| 223 | + }, |
| 224 | + "passwordChangeCommand": { |
| 225 | + "type": "object", |
| 226 | + "additionalProperties": true, |
| 227 | + "description": "Which password-change command path the target supports (passwd, chpasswd, vendor-specific CLI, etc.) — observed, not assumed." |
| 228 | + } |
| 229 | + } |
| 230 | + }, |
| 231 | + "httpFindings": { |
| 232 | + "type": "object", |
| 233 | + "description": "HTTP-specific finding shapes. Fields below are the categories the playbook MUST cover; their internal shape is intentionally permissive in v0 and will be tightened once more HTTP targets have been probed.", |
| 234 | + "additionalProperties": false, |
| 235 | + "properties": { |
| 236 | + "authScheme": { |
| 237 | + "type": "object", |
| 238 | + "additionalProperties": true, |
| 239 | + "description": "Which authentication scheme(s) the target accepts (basic, bearer, api-key header, form-fill, cookie). Observed via WWW-Authenticate, login form inspection, etc." |
| 240 | + }, |
| 241 | + "loginForm": { |
| 242 | + "type": "object", |
| 243 | + "additionalProperties": true, |
| 244 | + "description": "If form-fill is in play: form action URL, field names, hidden tokens (CSRF), redirect chain." |
| 245 | + }, |
| 246 | + "cookieBehavior": { |
| 247 | + "type": "object", |
| 248 | + "additionalProperties": true, |
| 249 | + "description": "Session cookie names, flags, lifetimes; whether session cookies suffice for subsequent calls." |
| 250 | + }, |
| 251 | + "apiDiscovery": { |
| 252 | + "type": "object", |
| 253 | + "additionalProperties": true, |
| 254 | + "description": "Discovered API endpoints relevant to the planned operations (e.g., user lookup, password change, key rotation). Sourced from vendor docs or probe responses; never invented." |
| 255 | + } |
| 256 | + } |
| 257 | + } |
| 258 | + } |
| 259 | +} |
0 commit comments