@agent-ix/spec-objects-security 0.5.0 → 0.8.0
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.
- package/README.md +2 -0
- package/manifest.yaml +270 -26
- package/package.json +8 -2
- package/schemas/Asset.json +78 -0
- package/schemas/AttackSurface.json +55 -0
- package/schemas/AuditEvent.json +57 -0
- package/schemas/AuditFinding.json +67 -0
- package/schemas/AuthFlow.json +69 -0
- package/schemas/ConfidentialityLevel.json +13 -0
- package/schemas/Control.json +83 -0
- package/schemas/ControlEffectiveness.json +12 -0
- package/schemas/ControlMapping.json +26 -0
- package/schemas/CorsPolicy.json +46 -0
- package/schemas/CsrfToken.json +46 -0
- package/schemas/DataClassification.json +61 -0
- package/schemas/DefaultedField.json +14 -0
- package/schemas/EffectivenessField.json +15 -0
- package/schemas/EncryptionKey.json +78 -0
- package/schemas/FindingStatus.json +14 -0
- package/schemas/FlowStep.json +24 -0
- package/schemas/IdentityField.json +15 -0
- package/schemas/Impact.json +14 -0
- package/schemas/ImpactField.json +15 -0
- package/schemas/JwtClaim.json +49 -0
- package/schemas/LevelField.json +15 -0
- package/schemas/Likelihood.json +14 -0
- package/schemas/LikelihoodField.json +15 -0
- package/schemas/MfaFactorKind.json +12 -0
- package/schemas/MfaMethod.json +69 -0
- package/schemas/OccurrenceField.json +14 -0
- package/schemas/OccurrenceTypeRef.json +15 -0
- package/schemas/PasswordPolicy.json +40 -0
- package/schemas/Permission.json +49 -0
- package/schemas/Policy.json +52 -0
- package/schemas/Risk.json +79 -0
- package/schemas/Role.json +55 -0
- package/schemas/Scope.json +49 -0
- package/schemas/Secret.json +78 -0
- package/schemas/SecretLifecycle.json +14 -0
- package/schemas/SessionConfig.json +43 -0
- package/schemas/Severity.json +14 -0
- package/schemas/SeverityField.json +15 -0
- package/schemas/StatusField.json +15 -0
- package/schemas/StrideCategory.json +15 -0
- package/schemas/StrideCategoryField.json +15 -0
- package/schemas/Threat.json +67 -0
- package/schemas/TrustBoundary.json +69 -0
- package/schemas/TrustLevel.json +12 -0
- package/schemas/TrustLevelField.json +15 -0
- package/schemas/Vulnerability.json +70 -0
- package/schemas/toolchain.json +97 -0
- package/skeletons/asset.md +22 -14
- package/skeletons/asset.sysml.md +27 -0
- package/skeletons/attack_surface.md +21 -18
- package/skeletons/audit_event.md +31 -18
- package/skeletons/audit_finding.md +22 -18
- package/skeletons/auth_flow.md +56 -21
- package/skeletons/control.md +45 -16
- package/skeletons/cors_policy.md +33 -17
- package/skeletons/csrf_token.md +17 -13
- package/skeletons/data_classification.md +23 -18
- package/skeletons/encryption_key.md +19 -12
- package/skeletons/jwt_claim.md +25 -14
- package/skeletons/mfa_method.md +17 -11
- package/skeletons/password_policy.md +35 -20
- package/skeletons/permission.md +18 -12
- package/skeletons/policy.md +33 -17
- package/skeletons/risk.md +20 -14
- package/skeletons/role.md +20 -13
- package/skeletons/scope.md +18 -12
- package/skeletons/secret.md +23 -16
- package/skeletons/secret.sysml.md +29 -0
- package/skeletons/session_config.md +35 -18
- package/skeletons/threat.md +22 -11
- package/skeletons/threat.sysml.md +26 -0
- package/skeletons/trust_boundary.md +51 -16
- package/skeletons/vulnerability.md +18 -15
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: SURF-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "PublicTokenEndpoint"
|
|
4
4
|
type: attack_surface
|
|
5
|
+
object: attack_surface
|
|
5
6
|
---
|
|
6
|
-
<!-- attack_surface authoring skeleton (spec-objects-security). Fill every
|
|
7
|
-
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
attack_surface
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
# [SURF-001]
|
|
13
|
-
|
|
14
|
-
Internet-reachable surface of the Atlas authentication subsystem, reviewed
|
|
15
|
-
whenever a new route crosses BOUND-001 outward.
|
|
7
|
+
<!-- attack_surface authoring skeleton (spec-objects-security). Fill every section with
|
|
8
|
+
substantive content. Contract (manifest body_extraction asserts):
|
|
9
|
+
- Frontmatter MUST carry id, title, type: attack_surface,
|
|
10
|
+
object: attack_surface.
|
|
11
|
+
- "## Entry Points" (H2, required): the reachable entry points.
|
|
12
|
+
- "## Properties" (H2): the typed declaration. -->
|
|
13
|
+
# [SURF-001] PublicTokenEndpoint
|
|
16
14
|
|
|
17
15
|
## Entry Points
|
|
18
16
|
|
|
19
|
-
- `
|
|
20
|
-
- `POST /
|
|
21
|
-
- `
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
- `POST /oauth/token` — authorization-code and refresh-token grants.
|
|
18
|
+
- `POST /oauth/revoke` — grant-family revocation.
|
|
19
|
+
- `GET /.well-known/openid-configuration` — unauthenticated metadata.
|
|
20
|
+
|
|
21
|
+
## Properties
|
|
22
|
+
|
|
23
|
+
| Field | Type | Multiplicity | Constraints |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| surface_id | UUID | 1..1 | identity |
|
|
26
|
+
| transport | String | 1..1 | minLength: 1 |
|
|
27
|
+
| internet_reachable | Boolean | 1..1 | |
|
|
28
|
+
| rate_limit_per_minute | Integer | 0..1 | min: 1 |
|
package/skeletons/audit_event.md
CHANGED
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: AUDIT-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "TokenReuseDetected"
|
|
4
4
|
type: audit_event
|
|
5
|
+
object: audit_event
|
|
5
6
|
---
|
|
6
|
-
<!-- audit_event authoring skeleton (spec-objects-security). Fill every
|
|
7
|
-
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
audit_event
|
|
10
|
-
-
|
|
11
|
-
event
|
|
12
|
-
|
|
7
|
+
<!-- audit_event authoring skeleton (spec-objects-security). Fill every section with
|
|
8
|
+
substantive content. Contract (manifest body_extraction asserts):
|
|
9
|
+
- Frontmatter MUST carry id, title, type: audit_event,
|
|
10
|
+
object: audit_event.
|
|
11
|
+
- "## Properties" (H2): the declared payload as typed rows. An audit
|
|
12
|
+
event declaration carries NO identity field (occurrence identity
|
|
13
|
+
belongs to the runtime record) and at least one `Timestamp`
|
|
14
|
+
occurrence field; no row carries a default.
|
|
15
|
+
- "## Event Schema" (H2, required) holds a fenced `json` block. It is a
|
|
16
|
+
derived, human-facing view; the typed table is the authority. -->
|
|
17
|
+
# [AUDIT-001] TokenReuseDetected
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
TokenReuseDetected is emitted when an already-rotated refresh token is
|
|
20
|
+
presented. The whole grant family is revoked and the session terminated.
|
|
21
|
+
|
|
22
|
+
## Properties
|
|
23
|
+
|
|
24
|
+
| Field | Type | Multiplicity | Constraints |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| occurred_at | Timestamp | 1..1 | |
|
|
27
|
+
| actor_reference | String | 1..1 | minLength: 1 |
|
|
28
|
+
| grant_family_reference | String | 1..1 | minLength: 1 |
|
|
29
|
+
| source_address | String | 0..1 | minLength: 1 |
|
|
17
30
|
|
|
18
31
|
## Event Schema
|
|
19
32
|
|
|
20
33
|
```json
|
|
21
34
|
{
|
|
35
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
36
|
+
"$id": "https://specs.agent-ix.dev/audit/token-reuse-detected.schema.json",
|
|
37
|
+
"title": "TokenReuseDetected",
|
|
22
38
|
"type": "object",
|
|
23
|
-
"required": ["
|
|
39
|
+
"required": ["occurred_at", "actor_reference", "grant_family_reference"],
|
|
24
40
|
"properties": {
|
|
25
|
-
"event": { "const": "user.login.succeeded" },
|
|
26
41
|
"occurred_at": { "type": "string", "format": "date-time" },
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"idp_issuer": { "type": "string", "format": "uri" },
|
|
31
|
-
"mfa_method": { "type": "string", "enum": ["totp", "webauthn", "none"] }
|
|
42
|
+
"actor_reference": { "type": "string", "minLength": 1 },
|
|
43
|
+
"grant_family_reference": { "type": "string", "minLength": 1 },
|
|
44
|
+
"source_address": { "type": "string", "minLength": 1 }
|
|
32
45
|
}
|
|
33
46
|
}
|
|
34
47
|
```
|
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: FIND-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "MissingTokenRotation"
|
|
4
4
|
type: audit_finding
|
|
5
|
+
object: audit_finding
|
|
5
6
|
---
|
|
6
|
-
<!-- audit_finding authoring skeleton (spec-objects-security). Fill every
|
|
7
|
-
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
audit_finding
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
(ASSET-001) with a credential that retains `EVAL`/`SCRIPT` privileges,
|
|
15
|
-
unnecessarily exposing the Lua sandbox surface of VULN-001 to any service
|
|
16
|
-
compromise. Severity high; affected component is the shared Redis ACL profile.
|
|
7
|
+
<!-- audit_finding authoring skeleton (spec-objects-security). Fill every section with
|
|
8
|
+
substantive content. Contract (manifest body_extraction asserts):
|
|
9
|
+
- Frontmatter MUST carry id, title, type: audit_finding,
|
|
10
|
+
object: audit_finding.
|
|
11
|
+
- "## Recommendation" (H2, required): what the auditor asks for.
|
|
12
|
+
- "## Properties" (H2): the typed declaration. AuditFinding.json
|
|
13
|
+
requires a `status` row, so an untriaged finding is refused. -->
|
|
14
|
+
# [FIND-001] MissingTokenRotation
|
|
17
15
|
|
|
18
16
|
## Recommendation
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
Enable refresh-token rotation with reuse detection on every tenant IdP
|
|
19
|
+
integration, and fail the release gate while any integration is without it.
|
|
20
|
+
Re-audit thirty days after the change lands.
|
|
21
|
+
|
|
22
|
+
## Properties
|
|
23
|
+
|
|
24
|
+
| Field | Type | Multiplicity | Constraints |
|
|
25
|
+
|---|---|---|---|
|
|
26
|
+
| finding_id | UUID | 1..1 | identity |
|
|
27
|
+
| status | String | 1..1 | minLength: 1 |
|
|
28
|
+
| observed_at | Timestamp | 1..1 | |
|
|
29
|
+
| traced_risk | TenantDataExfiltration | 0..1 | |
|
package/skeletons/auth_flow.md
CHANGED
|
@@ -1,31 +1,66 @@
|
|
|
1
1
|
---
|
|
2
|
-
id:
|
|
3
|
-
title: "
|
|
2
|
+
id: AUTH-001
|
|
3
|
+
title: "AuthorizationCodeWithPkce"
|
|
4
4
|
type: auth_flow
|
|
5
|
+
object: auth_flow
|
|
5
6
|
---
|
|
6
|
-
<!-- auth_flow authoring skeleton (spec-objects-security). Fill every
|
|
7
|
+
<!-- auth_flow authoring skeleton (spec-objects-security). Fill every section with
|
|
7
8
|
substantive content. Contract (manifest body_extraction asserts):
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
- Frontmatter MUST carry id, title, type: auth_flow, object: auth_flow.
|
|
10
|
+
- "## Flow" (H2, required) holds a fenced `mermaid` diagram.
|
|
11
|
+
- "## Operations" (H2): one `### <name>` per exchange, an optional param
|
|
12
|
+
table, a `Returns: <Type>[<multiplicity>]` line and optional Pre:/Post:
|
|
13
|
+
lines. AuthFlow.json requires at least one operation — a flow is its
|
|
14
|
+
exchanges. -->
|
|
15
|
+
# [AUTH-001] AuthorizationCodeWithPkce
|
|
15
16
|
|
|
16
17
|
## Flow
|
|
17
18
|
|
|
18
19
|
```mermaid
|
|
19
20
|
sequenceDiagram
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
AtlasApp->>IdP: POST /token with code and code_verifier
|
|
29
|
-
IdP->>AtlasApp: ID token plus access and refresh tokens
|
|
30
|
-
AtlasApp->>Browser: Set __Host-atlas_session cookie and redirect
|
|
21
|
+
participant U as User agent
|
|
22
|
+
participant C as Client
|
|
23
|
+
participant A as Authorization server
|
|
24
|
+
C->>A: authorize with code_challenge
|
|
25
|
+
A->>U: prompt and consent
|
|
26
|
+
U->>C: authorization code
|
|
27
|
+
C->>A: exchange code with code_verifier
|
|
28
|
+
A->>C: access token and refresh token
|
|
31
29
|
```
|
|
30
|
+
|
|
31
|
+
## Operations
|
|
32
|
+
|
|
33
|
+
The exchanges this flow performs. Each operation owns one `### <name>`
|
|
34
|
+
heading; the param table is the typed declaration of its inputs.
|
|
35
|
+
|
|
36
|
+
### authorize
|
|
37
|
+
|
|
38
|
+
Start the flow and obtain an authorization code.
|
|
39
|
+
|
|
40
|
+
| Param | Type | Multiplicity | Constraints |
|
|
41
|
+
|---|---|---|---|
|
|
42
|
+
| code_challenge | String | 1..1 | minLength: 43 |
|
|
43
|
+
| redirect_uri | String | 1..1 | minLength: 1 |
|
|
44
|
+
|
|
45
|
+
Returns: String[1..1]
|
|
46
|
+
|
|
47
|
+
### exchange_code
|
|
48
|
+
|
|
49
|
+
Exchange the code and verifier for a token pair.
|
|
50
|
+
|
|
51
|
+
| Param | Type | Multiplicity | Constraints |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| code | String | 1..1 | minLength: 1 |
|
|
54
|
+
| code_verifier | String | 1..1 | minLength: 43 |
|
|
55
|
+
|
|
56
|
+
Returns: Boolean[1..1]
|
|
57
|
+
|
|
58
|
+
### refresh
|
|
59
|
+
|
|
60
|
+
Rotate the grant family and issue a fresh token pair.
|
|
61
|
+
|
|
62
|
+
| Param | Type | Multiplicity | Constraints |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| presented_token_locator | String | 1..1 | minLength: 1 |
|
|
65
|
+
|
|
66
|
+
Returns: Boolean[1..1]
|
package/skeletons/control.md
CHANGED
|
@@ -1,24 +1,53 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: CTRL-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "RefreshTokenRotation"
|
|
4
4
|
type: control
|
|
5
|
+
object: control
|
|
5
6
|
---
|
|
6
|
-
<!-- control authoring skeleton (spec-objects-security). Fill every
|
|
7
|
+
<!-- control authoring skeleton (spec-objects-security). Fill every section with
|
|
7
8
|
substantive content. Contract (manifest body_extraction asserts):
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
the whole family compromised: all descendants are revoked, the session is
|
|
16
|
-
terminated, and a `token.reuse.detected` audit event fires.
|
|
9
|
+
- Frontmatter MUST carry id, title, type: control, object: control.
|
|
10
|
+
- "## Mappings" (H2, required): the threats, risks and standards this
|
|
11
|
+
control addresses.
|
|
12
|
+
- "## Properties" (H2): Control.json requires an `effectiveness` row, so
|
|
13
|
+
effectiveness is always stated and never assumed.
|
|
14
|
+
- "## Invariants" (H2): Control.json requires at least one clause. -->
|
|
15
|
+
# [CTRL-001] RefreshTokenRotation
|
|
17
16
|
|
|
18
17
|
## Mappings
|
|
19
18
|
|
|
20
|
-
- Mitigates
|
|
21
|
-
- Reduces
|
|
22
|
-
- Implements OAuth 2.0 Security BCP (RFC 9700) refresh-token rotation guidance
|
|
23
|
-
- Maps to OWASP ASVS v4
|
|
24
|
-
|
|
19
|
+
- Mitigates RefreshTokenReplay (stolen refresh token replay).
|
|
20
|
+
- Reduces TenantDataExfiltration likelihood from possible to unlikely.
|
|
21
|
+
- Implements OAuth 2.0 Security BCP (RFC 9700) refresh-token rotation guidance.
|
|
22
|
+
- Maps to OWASP ASVS v4 3.5.2 and NIST SP 800-63B 7.1 session binding.
|
|
23
|
+
|
|
24
|
+
## Properties
|
|
25
|
+
|
|
26
|
+
| Field | Type | Multiplicity | Constraints |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| control_id | UUID | 1..1 | identity |
|
|
29
|
+
| effectiveness | String | 1..1 | minLength: 1 |
|
|
30
|
+
| owner | String | 1..1 | minLength: 1 |
|
|
31
|
+
| last_assessed_at | Timestamp | 1..1 | |
|
|
32
|
+
|
|
33
|
+
## Invariants
|
|
34
|
+
|
|
35
|
+
The clauses this control enforces. Each clause owns one `ocl` fence under its
|
|
36
|
+
own `### <clauseId>` heading; the fence text is carried verbatim and never
|
|
37
|
+
evaluated here.
|
|
38
|
+
|
|
39
|
+
### EveryExchangeInvalidatesThePresentedToken
|
|
40
|
+
|
|
41
|
+
```ocl
|
|
42
|
+
context RefreshTokenRotation
|
|
43
|
+
inv EveryExchangeInvalidatesThePresentedToken:
|
|
44
|
+
self.effectiveness <> 'not_assessed' implies self.last_assessed_at->notEmpty()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### ReuseRevokesTheWholeFamily
|
|
48
|
+
|
|
49
|
+
```ocl
|
|
50
|
+
context RefreshTokenRotation
|
|
51
|
+
inv ReuseRevokesTheWholeFamily:
|
|
52
|
+
self.owner->notEmpty()
|
|
53
|
+
```
|
package/skeletons/cors_policy.md
CHANGED
|
@@ -1,24 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: CORS-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "TenantApiCorsPolicy"
|
|
4
4
|
type: cors_policy
|
|
5
|
+
object: cors_policy
|
|
5
6
|
---
|
|
6
|
-
<!-- cors_policy authoring skeleton (spec-objects-security). Fill every
|
|
7
|
-
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
cors_policy
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Browser cross-origin policy enforced by the API gateway for `api.atlas.example`.
|
|
14
|
-
Credentials are only honored for first-party app origins; integration origins
|
|
15
|
-
get token-based access without cookies.
|
|
7
|
+
<!-- cors_policy authoring skeleton (spec-objects-security). Fill every section with
|
|
8
|
+
substantive content. Contract (manifest body_extraction asserts):
|
|
9
|
+
- Frontmatter MUST carry id, title, type: cors_policy,
|
|
10
|
+
object: cors_policy.
|
|
11
|
+
- "## Origins" (H2, required): the allowed origins.
|
|
12
|
+
- "## Invariants" (H2): CorsPolicy.json requires at least one clause. -->
|
|
13
|
+
# [CORS-001] TenantApiCorsPolicy
|
|
16
14
|
|
|
17
15
|
## Origins
|
|
18
16
|
|
|
19
|
-
- `https://app.
|
|
20
|
-
- `https
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
- `https://app.example.com` — the first-party tenant console.
|
|
18
|
+
- `https://*.tenant.example.com` — per-tenant vanity hosts, exact-suffix matched.
|
|
19
|
+
- No wildcard origin, and no origin is echoed back unvalidated.
|
|
20
|
+
|
|
21
|
+
## Invariants
|
|
22
|
+
|
|
23
|
+
The clauses this policy asserts. Each clause owns one `ocl` fence under its
|
|
24
|
+
own `### <clauseId>` heading.
|
|
25
|
+
|
|
26
|
+
### NoWildcardOrigin
|
|
27
|
+
|
|
28
|
+
```ocl
|
|
29
|
+
context TenantApiCorsPolicy
|
|
30
|
+
inv NoWildcardOrigin:
|
|
31
|
+
self.allowed_origins->excludes('*')
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### CredentialsNeverWithWildcard
|
|
35
|
+
|
|
36
|
+
```ocl
|
|
37
|
+
context TenantApiCorsPolicy
|
|
38
|
+
inv CredentialsNeverWithWildcard:
|
|
39
|
+
self.allow_credentials implies self.allowed_origins->size() > 0
|
|
40
|
+
```
|
package/skeletons/csrf_token.md
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: CSRF-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "SessionAntiForgeryToken"
|
|
4
4
|
type: csrf_token
|
|
5
|
-
|
|
5
|
+
object: csrf_token
|
|
6
|
+
rotation_window: PT30M
|
|
6
7
|
---
|
|
7
|
-
<!-- csrf_token authoring skeleton (spec-objects-security). Fill every
|
|
8
|
+
<!-- csrf_token authoring skeleton (spec-objects-security). Fill every section with
|
|
8
9
|
substantive content. Contract (manifest body_extraction asserts):
|
|
9
|
-
- Frontmatter MUST carry id, title, type
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
- Frontmatter MUST carry id, title, type: csrf_token, object: csrf_token
|
|
11
|
+
and rotation_window.
|
|
12
|
+
- "## Properties" (H2): CsrfToken.json admits no field carrying a
|
|
13
|
+
default, so no token value appears in the declaration. -->
|
|
14
|
+
# [CSRF-001] SessionAntiForgeryToken
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
## Properties
|
|
17
|
+
|
|
18
|
+
| Field | Type | Multiplicity | Constraints |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| token_id | UUID | 1..1 | identity |
|
|
21
|
+
| locator | String | 1..1 | minLength: 1 |
|
|
22
|
+
| bound_session_attribute | String | 1..1 | minLength: 1 |
|
|
23
|
+
| rotation_window | Duration | 1..1 | |
|
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: CLASS-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "DataRestricted"
|
|
4
4
|
type: data_classification
|
|
5
|
+
object: data_classification
|
|
5
6
|
---
|
|
6
|
-
<!-- data_classification authoring skeleton (spec-objects-security). Fill every
|
|
7
|
-
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
data_classification
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
phone numbers) and any document flagged as containing personal data. Sits one
|
|
15
|
-
level below `Restricted` (secrets and key material) in the Atlas scheme.
|
|
7
|
+
<!-- data_classification authoring skeleton (spec-objects-security). Fill every section with
|
|
8
|
+
substantive content. Contract (manifest body_extraction asserts):
|
|
9
|
+
- Frontmatter MUST carry id, title, type: data_classification,
|
|
10
|
+
object: data_classification.
|
|
11
|
+
- "## Handling" (H2, required): how data of this class is handled.
|
|
12
|
+
- "## Properties" (H2): the typed declaration. DataClassification.json
|
|
13
|
+
requires a `level` row. -->
|
|
14
|
+
# [CLASS-001] DataRestricted
|
|
16
15
|
|
|
17
16
|
## Handling
|
|
18
17
|
|
|
19
|
-
- Encrypted at rest with
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
- Encrypted at rest with TenantDataEncryptionKey and in transit with TLS 1.3.
|
|
19
|
+
- Never written to application logs, traces, or error payloads.
|
|
20
|
+
- Exported only under ExportTenantData, and only to the owning tenant.
|
|
21
|
+
- Deleted within the retention period once the tenant contract ends.
|
|
22
|
+
|
|
23
|
+
## Properties
|
|
24
|
+
|
|
25
|
+
| Field | Type | Multiplicity | Constraints |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| classification_id | UUID | 1..1 | identity |
|
|
28
|
+
| level | String | 1..1 | minLength: 1 |
|
|
29
|
+
| retention | Duration | 1..1 | |
|
|
30
|
+
| logging_permitted | Boolean | 1..1 | |
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: KEY-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "TenantDataEncryptionKey"
|
|
4
4
|
type: encryption_key
|
|
5
|
+
object: encryption_key
|
|
5
6
|
algorithm: AES-256-GCM
|
|
6
|
-
rotation:
|
|
7
|
+
rotation: P90D
|
|
7
8
|
---
|
|
8
|
-
<!-- encryption_key authoring skeleton (spec-objects-security). Fill every
|
|
9
|
-
|
|
10
|
-
- Frontmatter MUST carry id, title, type
|
|
11
|
-
encryption_key
|
|
12
|
-
|
|
9
|
+
<!-- encryption_key authoring skeleton (spec-objects-security). Fill every section with
|
|
10
|
+
substantive content. Contract (manifest body_extraction asserts):
|
|
11
|
+
- Frontmatter MUST carry id, title, type: encryption_key,
|
|
12
|
+
object: encryption_key and algorithm; rotation is optional.
|
|
13
|
+
- "## Properties" (H2): the typed declaration. EncryptionKey.json admits
|
|
14
|
+
no field carrying a default, so key material is referenced, never held. -->
|
|
15
|
+
# [KEY-001] TenantDataEncryptionKey
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
## Properties
|
|
18
|
+
|
|
19
|
+
| Field | Type | Multiplicity | Constraints |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| key_id | UUID | 1..1 | identity |
|
|
22
|
+
| locator | String | 1..1 | minLength: 1 |
|
|
23
|
+
| lifecycle | String | 1..1 | minLength: 1 |
|
|
24
|
+
| key_length_bits | Integer | 1..1 | min: 256 |
|
|
25
|
+
| rotation_period | Duration | 1..1 | |
|
package/skeletons/jwt_claim.md
CHANGED
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: CLAIM-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "TenantIdentifierClaim"
|
|
4
4
|
type: jwt_claim
|
|
5
|
+
object: jwt_claim
|
|
5
6
|
---
|
|
6
|
-
<!-- jwt_claim authoring skeleton (spec-objects-security). Fill every
|
|
7
|
+
<!-- jwt_claim authoring skeleton (spec-objects-security). Fill every section with
|
|
7
8
|
substantive content. Contract (manifest body_extraction asserts):
|
|
8
|
-
- Frontmatter MUST carry id, title, type
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
- Frontmatter MUST carry id, title, type: jwt_claim, object: jwt_claim.
|
|
10
|
+
- "## Schema" (H2, required) holds a fenced `json` block. It is a
|
|
11
|
+
derived, human-facing view; the typed table is the authority.
|
|
12
|
+
- "## Properties" (H2): JwtClaim.json admits no field carrying a
|
|
13
|
+
default, so no claim value is written into the declaration. -->
|
|
14
|
+
# [CLAIM-001] TenantIdentifierClaim
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
## Properties
|
|
17
|
+
|
|
18
|
+
| Field | Type | Multiplicity | Constraints |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| claim_id | UUID | 1..1 | identity |
|
|
21
|
+
| claim_name | String | 1..1 | minLength: 1, maxLength: 32 |
|
|
22
|
+
| value_type | String | 1..1 | minLength: 1 |
|
|
23
|
+
| required_in_access_token | Boolean | 1..1 | |
|
|
17
24
|
|
|
18
25
|
## Schema
|
|
19
26
|
|
|
20
27
|
```json
|
|
21
28
|
{
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
29
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
30
|
+
"$id": "https://specs.agent-ix.dev/claims/tenant-identifier.schema.json",
|
|
31
|
+
"title": "TenantIdentifierClaim",
|
|
32
|
+
"type": "object",
|
|
33
|
+
"required": ["tid"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"tid": { "type": "string", "format": "uuid" }
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
```
|
package/skeletons/mfa_method.md
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: MFA-001
|
|
3
|
-
title: "
|
|
3
|
+
title: "TimeBasedOneTimeCode"
|
|
4
4
|
type: mfa_method
|
|
5
|
+
object: mfa_method
|
|
5
6
|
kind: totp
|
|
6
7
|
factor: possession
|
|
7
8
|
---
|
|
8
|
-
<!-- mfa_method authoring skeleton (spec-objects-security). Fill every
|
|
9
|
+
<!-- mfa_method authoring skeleton (spec-objects-security). Fill every section with
|
|
9
10
|
substantive content. Contract (manifest body_extraction asserts):
|
|
10
|
-
- Frontmatter MUST carry id, title, type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
- Frontmatter MUST carry id, title, type: mfa_method, object: mfa_method
|
|
12
|
+
and kind; factor is optional.
|
|
13
|
+
- "## Properties" (H2): the typed declaration. MfaMethod.json admits no
|
|
14
|
+
field carrying a default, so no enrolment value can be embedded. -->
|
|
15
|
+
# [MFA-001] TimeBasedOneTimeCode
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
## Properties
|
|
18
|
+
|
|
19
|
+
| Field | Type | Multiplicity | Constraints |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| method_id | UUID | 1..1 | identity |
|
|
22
|
+
| factor_kind | String | 1..1 | minLength: 1 |
|
|
23
|
+
| code_digits | Integer | 1..1 | min: 6, max: 8 |
|
|
24
|
+
| step_period | Duration | 1..1 | |
|
|
25
|
+
| seed_locator | String | 1..1 | minLength: 1 |
|