@intentius/terragucci 0.4.2 → 0.4.4
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 +1 -0
- package/dist/audit.schema.json +34 -0
- package/dist/changes.schema.json +33 -0
- package/dist/dora.schema.json +104 -0
- package/dist/estate.schema.json +250 -0
- package/dist/history.schema.json +49 -0
- package/dist/inventory.schema.json +38 -0
- package/dist/notify.schema.json +66 -0
- package/dist/report-index.schema.json +67 -0
- package/dist/report.schema.json +137 -2
- package/dist/run.schema.json +88 -0
- package/dist/state-versions.schema.json +42 -0
- package/dist/terragucci.mjs +639 -393
- package/dist/terragucci.mjs.map +4 -4
- package/dist/types.d.ts +150 -9
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ A root is a directory whose Terraform files declare a backend or configure a pro
|
|
|
23
23
|
|---|---|
|
|
24
24
|
| `terragucci init` | sets one repo up; `--forge` and `--binary` override detection, `--dry-run` writes nothing |
|
|
25
25
|
| `terragucci reconcile --config <file>` | from a control repo, previews every project's pipeline; `--mode apply` opens a pull request in each project that changes |
|
|
26
|
+
| `terragucci generate` | writes each root's backend, provider and version files from the `generate` key; `--check` fails on one that differs |
|
|
26
27
|
| `terragucci plan` | plans this repo's roots in apply order; `--root <glob>` narrows it |
|
|
27
28
|
|
|
28
29
|
| Exit code | Means |
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/audit/v1/audit.schema.json",
|
|
4
|
+
"title": "terragucci.audit/v1",
|
|
5
|
+
"description": "One line of audit.jsonl at the top of a reports prefix: an approval, apply, policy override, refused wave or state migration. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "id", "kind", "project", "at", "who", "what", "digest", "result", "evidence"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.audit/v1" },
|
|
10
|
+
"id": { "type": "string", "description": "sha256: over where the entry came from; the same records give the same id." },
|
|
11
|
+
"kind": { "enum": ["approval-requested", "approval", "approval-revoked", "override-requested", "override", "override-revoked", "apply", "refused", "migration", "unlock"] },
|
|
12
|
+
"project": { "type": "string", "description": "<host>/<path> of the repo." },
|
|
13
|
+
"at": { "type": "string", "description": "When it happened, ISO 8601." },
|
|
14
|
+
"who": { "type": ["string", "null"], "description": "The approver, the overrider, whoever removed the line, or for an apply the approver it applied under. Null when nobody did." },
|
|
15
|
+
"what": { "type": "string", "description": "The gate (wave-<k>, or a migration's name) or, for an override, the root." },
|
|
16
|
+
"digest": { "type": ["string", "null"], "description": "The wave's set digest, or the digest an override binds. Null when a root failed to plan." },
|
|
17
|
+
"result": { "type": "string" },
|
|
18
|
+
"evidence": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"required": ["source"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"source": { "enum": ["ledger", "report"] },
|
|
23
|
+
"branch": { "type": "string" },
|
|
24
|
+
"path": { "type": "string" },
|
|
25
|
+
"commit": { "type": "string" },
|
|
26
|
+
"bucket": { "type": "string" },
|
|
27
|
+
"key": { "type": "string" },
|
|
28
|
+
"url": { "type": "string" },
|
|
29
|
+
"job_url": { "type": "string" }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"detail": { "type": "object", "description": "What else the source says, by kind." }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/changes/v1/changes.schema.json",
|
|
4
|
+
"title": "terragucci.changes/v1",
|
|
5
|
+
"description": "changes.json in a project's directory of a reports prefix: one row per resource each applied tf-apply wave changed, newest first. Actions and attribute names, never a value. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "changes"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.changes/v1" },
|
|
10
|
+
"changes": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["address", "type", "actions", "attributes", "root", "commit", "finished", "path", "plan_digest", "set_digest"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"address": { "type": "string" },
|
|
17
|
+
"type": { "type": "string" },
|
|
18
|
+
"actions": { "type": "array", "items": { "enum": ["create", "update", "replace", "delete", "import", "move", "forget"] } },
|
|
19
|
+
"attributes": { "type": "array", "items": { "type": "string" }, "description": "The top-level attributes an update or a replacement changed, by name." },
|
|
20
|
+
"previous_address": { "type": "string", "description": "Where a moved resource was." },
|
|
21
|
+
"root": { "type": "string" },
|
|
22
|
+
"commit": { "type": "string" },
|
|
23
|
+
"wave": { "type": "integer" },
|
|
24
|
+
"finished": { "type": "string", "description": "When the wave finished." },
|
|
25
|
+
"path": { "type": "string", "description": "The wave's run directory, relative to the project's index.json." },
|
|
26
|
+
"plan_digest": { "type": ["string", "null"], "description": "The root's plan digest: the plan that applied." },
|
|
27
|
+
"set_digest": { "type": ["string", "null"], "description": "The wave's set digest, which its approval binds." },
|
|
28
|
+
"pull_request": { "type": "string" }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/dora/v1/dora.schema.json",
|
|
4
|
+
"title": "terragucci.dora/v1",
|
|
5
|
+
"description": "dora.json at the top of a reports prefix, beside estate.json: the four DORA metrics per project and for the estate, which terragucci estate builds from audit.jsonl and each project's index.json. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "generated", "weeks", "window", "drift_window_seconds", "audit", "estate", "projects"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.dora/v1" },
|
|
10
|
+
"generated": { "type": "string", "description": "When the metrics were built, ISO 8601." },
|
|
11
|
+
"weeks": { "type": "integer", "description": "How many weeks the metrics cover, the current one included." },
|
|
12
|
+
"window": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["from", "to"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"from": { "type": "string", "description": "The Monday, 00:00 UTC, the window starts on." },
|
|
17
|
+
"to": { "type": "string", "description": "When it ends: generated." }
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"drift_window_seconds": { "type": "integer", "description": "An applied wave whose roots drift within this long counts as a failed change." },
|
|
21
|
+
"audit": { "type": "boolean", "description": "Whether audit.jsonl was read. Without it no apply counts." },
|
|
22
|
+
"estate": { "$ref": "#/$defs/metrics" },
|
|
23
|
+
"projects": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"required": ["project", "deployments", "per_week", "lead_time", "change_failure", "restore", "trend"],
|
|
28
|
+
"properties": {
|
|
29
|
+
"project": { "type": "string" },
|
|
30
|
+
"deployments": { "type": "integer" },
|
|
31
|
+
"per_week": { "type": "number" },
|
|
32
|
+
"lead_time": { "$ref": "#/$defs/lead_time" },
|
|
33
|
+
"change_failure": { "$ref": "#/$defs/change_failure" },
|
|
34
|
+
"restore": { "$ref": "#/$defs/restore" },
|
|
35
|
+
"trend": { "$ref": "#/$defs/trend" }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"$defs": {
|
|
41
|
+
"seconds": { "type": ["integer", "null"], "description": "A median in seconds; null when nothing counts." },
|
|
42
|
+
"metrics": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"required": ["deployments", "per_week", "lead_time", "change_failure", "restore", "trend"],
|
|
45
|
+
"properties": {
|
|
46
|
+
"deployments": { "type": "integer", "description": "Applied waves in the window." },
|
|
47
|
+
"per_week": { "type": "number", "description": "Deployment frequency: applied waves per week over the window." },
|
|
48
|
+
"lead_time": { "$ref": "#/$defs/lead_time" },
|
|
49
|
+
"change_failure": { "$ref": "#/$defs/change_failure" },
|
|
50
|
+
"restore": { "$ref": "#/$defs/restore" },
|
|
51
|
+
"trend": { "$ref": "#/$defs/trend" }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"lead_time": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"description": "From a change's first plan to its wave applied.",
|
|
57
|
+
"required": ["changes", "median_seconds", "before_gate_seconds", "at_gate_seconds", "after_gate_seconds"],
|
|
58
|
+
"properties": {
|
|
59
|
+
"changes": { "type": "integer", "description": "Applied waves whose first plan was found." },
|
|
60
|
+
"median_seconds": { "$ref": "#/$defs/seconds" },
|
|
61
|
+
"before_gate_seconds": { "$ref": "#/$defs/seconds" },
|
|
62
|
+
"at_gate_seconds": { "$ref": "#/$defs/seconds" },
|
|
63
|
+
"after_gate_seconds": { "$ref": "#/$defs/seconds" }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"change_failure": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"required": ["applies", "failed", "drifted", "rate"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"applies": { "type": "integer", "description": "Waves that applied or failed. A refused or waiting wave is not an apply." },
|
|
71
|
+
"failed": { "type": "integer" },
|
|
72
|
+
"drifted": { "type": "integer", "description": "Applied waves whose roots drifted within drift_window_seconds." },
|
|
73
|
+
"rate": { "type": ["number", "null"], "description": "(failed + drifted) / applies; null with no applies." }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"restore": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"required": ["restored", "open", "median_seconds", "apply_restored", "drift_restored"],
|
|
79
|
+
"properties": {
|
|
80
|
+
"restored": { "type": "integer", "description": "Failed applies and drift restored in the window." },
|
|
81
|
+
"open": { "type": "integer", "description": "Failed roots no apply has restored yet, and drift no check has cleared." },
|
|
82
|
+
"median_seconds": { "$ref": "#/$defs/seconds" },
|
|
83
|
+
"apply_restored": { "type": "integer" },
|
|
84
|
+
"drift_restored": { "type": "integer" }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"trend": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"description": "One row per week, oldest first.",
|
|
90
|
+
"items": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"required": ["week", "deployments", "applies", "failures", "lead_time_seconds", "restore_seconds"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"week": { "type": "string", "description": "The Monday the week starts on, YYYY-MM-DD." },
|
|
95
|
+
"deployments": { "type": "integer" },
|
|
96
|
+
"applies": { "type": "integer" },
|
|
97
|
+
"failures": { "type": "integer", "description": "Failed applies and applied waves followed by drift." },
|
|
98
|
+
"lead_time_seconds": { "$ref": "#/$defs/seconds" },
|
|
99
|
+
"restore_seconds": { "$ref": "#/$defs/seconds" }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/estate/v1/estate.schema.json",
|
|
4
|
+
"title": "terragucci.estate/v1",
|
|
5
|
+
"description": "estate.json at the top of a reports prefix, which terragucci estate builds from every project's index.json, inventory.json and changes.json. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "generated", "totals", "projects", "recent"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.estate/v1" },
|
|
10
|
+
"generated": { "type": "string", "description": "When the page was built, ISO 8601. Every age on it is as of this time." },
|
|
11
|
+
"totals": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["projects", "waiting", "drifted_projects", "drifted_roots", "failed_roots", "unreadable"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"projects": { "type": "integer" },
|
|
16
|
+
"waiting": { "type": "integer", "description": "Waves waiting for an approval." },
|
|
17
|
+
"drifted_projects": { "type": "integer" },
|
|
18
|
+
"drifted_roots": { "type": "integer" },
|
|
19
|
+
"failed_roots": { "type": "integer" },
|
|
20
|
+
"unreadable": { "type": "integer", "description": "Projects whose index could not be read." },
|
|
21
|
+
"overridden_roots": { "type": "integer", "description": "Roots the newest apply waves applied under a policy override. Absent when none." },
|
|
22
|
+
"resources": { "type": "integer", "description": "Resources across every project's inventory. Absent when no project has one." }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"projects": { "type": "array", "items": { "$ref": "#/$defs/project" } },
|
|
26
|
+
"recent": { "type": "array", "description": "The 20 newest runs across every project, newest first.", "items": { "$ref": "#/$defs/run" } },
|
|
27
|
+
"audit": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"description": "The audit trail beside the page, when terragucci audit wrote one.",
|
|
30
|
+
"required": ["page", "entries", "generated"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"page": { "type": "string" },
|
|
33
|
+
"entries": { "type": "integer" },
|
|
34
|
+
"generated": { "type": "string" }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"history": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"description": "The resource history beside the page (history.json and history.html), when an apply changed a resource.",
|
|
40
|
+
"required": ["page", "resources", "generated"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"page": { "type": "string" },
|
|
43
|
+
"resources": { "type": "integer", "description": "Addresses with at least one apply." },
|
|
44
|
+
"generated": { "type": "string" }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"dora": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"description": "The DORA metrics beside the page (dora.json, terragucci.dora/v1).",
|
|
50
|
+
"required": ["file", "generated", "deployments"],
|
|
51
|
+
"properties": {
|
|
52
|
+
"file": { "type": "string" },
|
|
53
|
+
"generated": { "type": "string" },
|
|
54
|
+
"deployments": { "type": "integer", "description": "The estate's applied waves in the metrics' window." }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"graph": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "The dependency graph, from the run view of each project's newest applied commit: every root by wave, and an edge from each root to each root that reads its state through terraform_remote_state. An edge between two projects matched a read of a state outside the reader's project to the root of the other that holds it. Absent when no project has a run view.",
|
|
60
|
+
"required": ["nodes", "edges"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"nodes": {
|
|
63
|
+
"type": "array",
|
|
64
|
+
"items": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"required": ["project", "root", "wave"],
|
|
67
|
+
"properties": {
|
|
68
|
+
"project": { "type": "string" },
|
|
69
|
+
"root": { "type": "string" },
|
|
70
|
+
"wave": { "type": "integer" }
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"edges": {
|
|
75
|
+
"type": "array",
|
|
76
|
+
"description": "Each edge: to reads the state of from.",
|
|
77
|
+
"items": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"required": ["from", "to"],
|
|
80
|
+
"properties": {
|
|
81
|
+
"from": { "$ref": "#/$defs/graphRoot" },
|
|
82
|
+
"to": { "$ref": "#/$defs/graphRoot" }
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"$defs": {
|
|
90
|
+
"graphRoot": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"required": ["project", "root"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"project": { "type": "string" },
|
|
95
|
+
"root": { "type": "string" }
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"totals": {
|
|
99
|
+
"type": "object",
|
|
100
|
+
"required": ["create", "update", "replace", "delete"],
|
|
101
|
+
"properties": {
|
|
102
|
+
"create": { "type": "integer" },
|
|
103
|
+
"update": { "type": "integer" },
|
|
104
|
+
"replace": { "type": "integer" },
|
|
105
|
+
"delete": { "type": "integer" }
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"run": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"description": "A run, from its index row.",
|
|
111
|
+
"required": ["project", "commit", "stage", "finished", "roots", "refused", "totals", "destroys"],
|
|
112
|
+
"properties": {
|
|
113
|
+
"project": { "type": "string" },
|
|
114
|
+
"commit": { "type": "string" },
|
|
115
|
+
"stage": { "enum": ["tf-plan", "tf-apply", "tf-drift"] },
|
|
116
|
+
"wave": { "type": "integer" },
|
|
117
|
+
"share": { "type": "integer", "description": "The share of a tf-apply wave split across jobs." },
|
|
118
|
+
"finished": { "type": "string" },
|
|
119
|
+
"roots": { "type": "integer" },
|
|
120
|
+
"changed": { "type": "integer" },
|
|
121
|
+
"failed": { "type": "integer" },
|
|
122
|
+
"refused": { "type": "integer" },
|
|
123
|
+
"totals": { "$ref": "#/$defs/totals" },
|
|
124
|
+
"destroys": { "type": "integer", "description": "How many destroys and replacements the run has." },
|
|
125
|
+
"approval": { "enum": ["waiting", "approved", "not-required"] },
|
|
126
|
+
"waiting_since": { "type": "string" },
|
|
127
|
+
"applied": { "type": "string" },
|
|
128
|
+
"overridden": { "type": "integer" },
|
|
129
|
+
"report": { "type": "string", "description": "The run's report.html, relative to the page or absolute on another bucket's address. Absent when the page cannot link it." },
|
|
130
|
+
"pull_request": { "type": "string" },
|
|
131
|
+
"pull_request_url": { "type": "string" },
|
|
132
|
+
"job_url": { "type": "string" }
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"waiting": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"required": ["project", "wave", "commit", "since", "age_seconds"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"project": { "type": "string" },
|
|
140
|
+
"wave": { "type": "integer" },
|
|
141
|
+
"commit": { "type": "string" },
|
|
142
|
+
"since": { "type": "string", "description": "When the wave began waiting for an approval of its digest." },
|
|
143
|
+
"age_seconds": { "type": "integer", "description": "Seconds it had waited at generated." },
|
|
144
|
+
"report": { "type": "string" }
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"project": {
|
|
148
|
+
"type": "object",
|
|
149
|
+
"required": ["project", "status", "waiting", "drifted", "failed"],
|
|
150
|
+
"properties": {
|
|
151
|
+
"project": { "type": "string" },
|
|
152
|
+
"status": { "enum": ["ok", "no-index", "error"] },
|
|
153
|
+
"error": { "type": "string", "description": "Why the index could not be read." },
|
|
154
|
+
"index": { "type": "string", "description": "The project's index.html, when the page can link it." },
|
|
155
|
+
"plan": { "$ref": "#/$defs/run", "description": "The latest tf-plan." },
|
|
156
|
+
"drift": { "$ref": "#/$defs/run", "description": "The latest tf-drift." },
|
|
157
|
+
"apply": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"description": "The waves of the newest commit that ran tf-apply, by wave number.",
|
|
160
|
+
"required": ["commit", "waves"],
|
|
161
|
+
"properties": {
|
|
162
|
+
"commit": { "type": "string" },
|
|
163
|
+
"waves": { "type": "array", "items": { "$ref": "#/$defs/run" } }
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"waiting": { "type": "array", "items": { "$ref": "#/$defs/waiting" } },
|
|
167
|
+
"drifted": { "type": "integer", "description": "Roots that drifted in the latest drift check." },
|
|
168
|
+
"failed": { "type": "integer", "description": "Roots that failed in the latest plan, drift check and apply waves." },
|
|
169
|
+
"overridden": { "type": "integer", "description": "Roots the newest commit's apply waves applied under a policy override. Absent when none." },
|
|
170
|
+
"inventory": { "$ref": "#/$defs/inventory", "description": "The resources its roots hold, from its inventory.json. Absent until an apply records them." },
|
|
171
|
+
"states": { "type": "array", "description": "Each root's state versions, from its states.json. Absent until an apply records them.", "items": { "$ref": "#/$defs/stateRoot" } },
|
|
172
|
+
"run_view": {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"description": "The run view of the project's newest applied commit, which the dependency graph read: its commit, when a wave last wrote it, and its run.html when the page can link it. Absent until a wave writes one.",
|
|
175
|
+
"required": ["commit", "updated"],
|
|
176
|
+
"properties": {
|
|
177
|
+
"commit": { "type": "string" },
|
|
178
|
+
"updated": { "type": "string" },
|
|
179
|
+
"page": { "type": "string" }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"stateRoot": {
|
|
185
|
+
"type": "object",
|
|
186
|
+
"description": "One root's state: where it is, whether its backend keeps versions, and the version ids its applies left, newest first. Never the state's contents.",
|
|
187
|
+
"required": ["root", "backend", "versioning", "checked", "versions"],
|
|
188
|
+
"properties": {
|
|
189
|
+
"root": { "type": "string" },
|
|
190
|
+
"backend": { "type": "string" },
|
|
191
|
+
"location": { "type": "string" },
|
|
192
|
+
"versioning": { "enum": ["on", "off", "unknown"] },
|
|
193
|
+
"note": { "type": "string" },
|
|
194
|
+
"checked": { "type": "string", "description": "When the newest apply that recorded the root finished." },
|
|
195
|
+
"versions": {
|
|
196
|
+
"type": "array",
|
|
197
|
+
"items": {
|
|
198
|
+
"type": "object",
|
|
199
|
+
"required": ["version_id", "commit", "finished"],
|
|
200
|
+
"properties": {
|
|
201
|
+
"version_id": { "type": "string" },
|
|
202
|
+
"commit": { "type": "string" },
|
|
203
|
+
"finished": { "type": "string" },
|
|
204
|
+
"wave": { "type": "integer" },
|
|
205
|
+
"report": { "type": "string", "description": "The wave's report.html, when the page can link it." }
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"inventory": {
|
|
212
|
+
"type": "object",
|
|
213
|
+
"required": ["resources", "types", "roots"],
|
|
214
|
+
"properties": {
|
|
215
|
+
"resources": { "type": "integer" },
|
|
216
|
+
"types": {
|
|
217
|
+
"type": "array",
|
|
218
|
+
"description": "How many resources of each type, most first.",
|
|
219
|
+
"items": { "type": "object", "required": ["type", "count"], "properties": { "type": { "type": "string" }, "count": { "type": "integer" } } }
|
|
220
|
+
},
|
|
221
|
+
"roots": {
|
|
222
|
+
"type": "array",
|
|
223
|
+
"items": {
|
|
224
|
+
"type": "object",
|
|
225
|
+
"description": "One root's resources, as its newest applied wave left them.",
|
|
226
|
+
"required": ["root", "commit", "finished", "resources"],
|
|
227
|
+
"properties": {
|
|
228
|
+
"root": { "type": "string" },
|
|
229
|
+
"commit": { "type": "string" },
|
|
230
|
+
"finished": { "type": "string" },
|
|
231
|
+
"wave": { "type": "integer" },
|
|
232
|
+
"report": { "type": "string", "description": "The wave's report.html, when the page can link it." },
|
|
233
|
+
"resources": { "type": "array", "items": { "$ref": "#/$defs/resource" } }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"resource": {
|
|
240
|
+
"type": "object",
|
|
241
|
+
"required": ["address", "type", "provider"],
|
|
242
|
+
"properties": {
|
|
243
|
+
"address": { "type": "string" },
|
|
244
|
+
"type": { "type": "string" },
|
|
245
|
+
"provider": { "type": "string" },
|
|
246
|
+
"history": { "type": "string", "description": "Its section of history.html, when an apply changed it." }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/history/v1/history.schema.json",
|
|
4
|
+
"title": "terragucci.history/v1",
|
|
5
|
+
"description": "history.json at the top of a reports prefix, which terragucci estate builds from every project's changes.json and the audit trail: each resource address with every apply that changed it, oldest first. Actions and attribute names, never a value. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "generated", "audit", "resources"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.history/v1" },
|
|
10
|
+
"generated": { "type": "string" },
|
|
11
|
+
"audit": { "type": "boolean", "description": "Whether the audit trail was read for the approvers." },
|
|
12
|
+
"resources": {
|
|
13
|
+
"type": "array",
|
|
14
|
+
"items": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"required": ["id", "project", "root", "address", "type", "applies"],
|
|
17
|
+
"properties": {
|
|
18
|
+
"id": { "type": "string", "description": "Its anchor on history.html." },
|
|
19
|
+
"project": { "type": "string" },
|
|
20
|
+
"root": { "type": "string" },
|
|
21
|
+
"address": { "type": "string" },
|
|
22
|
+
"type": { "type": "string" },
|
|
23
|
+
"applies": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"description": "Oldest first.",
|
|
26
|
+
"items": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"required": ["actions", "attributes", "commit", "finished", "plan_digest", "set_digest"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"actions": { "type": "array", "items": { "enum": ["create", "update", "replace", "delete", "import", "move", "forget"] } },
|
|
31
|
+
"attributes": { "type": "array", "items": { "type": "string" } },
|
|
32
|
+
"previous_address": { "type": "string" },
|
|
33
|
+
"commit": { "type": "string" },
|
|
34
|
+
"wave": { "type": "integer" },
|
|
35
|
+
"finished": { "type": "string" },
|
|
36
|
+
"plan_digest": { "type": ["string", "null"] },
|
|
37
|
+
"set_digest": { "type": ["string", "null"] },
|
|
38
|
+
"approver": { "type": ["string", "null"], "description": "Who approved the wave, from its apply entry in the audit trail; null when no gate held it. Absent when the audit trail has no entry for the wave." },
|
|
39
|
+
"approval": { "type": "string", "description": "The id of the approval entry in the audit trail." },
|
|
40
|
+
"report": { "type": "string" },
|
|
41
|
+
"pull_request": { "type": "string" }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/inventory/v1/inventory.schema.json",
|
|
4
|
+
"title": "terragucci.inventory/v1",
|
|
5
|
+
"description": "inventory.json in a project's directory of a reports prefix: the resources each root holds, as its newest applied tf-apply wave left them. Addresses, types and providers, never a value. Within v1 fields are only added, and an existing field never changes meaning.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "roots"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.inventory/v1" },
|
|
10
|
+
"roots": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"description": "By root path.",
|
|
13
|
+
"items": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["root", "commit", "finished", "path", "resources"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"root": { "type": "string" },
|
|
18
|
+
"commit": { "type": "string" },
|
|
19
|
+
"finished": { "type": "string", "description": "When the wave that recorded the list finished." },
|
|
20
|
+
"wave": { "type": "integer" },
|
|
21
|
+
"path": { "type": "string", "description": "The wave's run directory, relative to the project's index.json." },
|
|
22
|
+
"resources": {
|
|
23
|
+
"type": "array",
|
|
24
|
+
"items": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["address", "type", "provider"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"address": { "type": "string" },
|
|
29
|
+
"type": { "type": "string" },
|
|
30
|
+
"provider": { "type": "string" }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://intentius.io/terragucci/schemas/notify/v1/notify.schema.json",
|
|
4
|
+
"title": "terragucci.notify/v1",
|
|
5
|
+
"description": "The event terragucci notify posts to the generic webhook when a tf-apply wave waits, is refused or fails. The schema changes only when a field is removed or changes meaning; new fields can appear without a bump.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["schema", "id", "event", "sent_at", "project", "wave", "roots"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"schema": { "const": "terragucci.notify/v1" },
|
|
10
|
+
"id": { "type": "string", "description": "sha256 hex over the project, the wave, the event and the set digest (the commit when there is none): the same for every post of one wave's event about one digest." },
|
|
11
|
+
"event": { "enum": ["waiting", "refused", "failed"] },
|
|
12
|
+
"sent_at": { "type": "string", "description": "When the job posted it, ISO 8601." },
|
|
13
|
+
"project": { "type": "string", "description": "<host>/<path> of the repo." },
|
|
14
|
+
"forge": { "enum": ["github", "gitlab", "forgejo"] },
|
|
15
|
+
"repo": { "type": "string", "description": "owner/name on GitHub and Forgejo, the project path on GitLab." },
|
|
16
|
+
"sha": { "type": "string", "description": "The commit the wave applied." },
|
|
17
|
+
"pr": { "type": "integer", "description": "The pull or merge request the job applied, when a comment started it." },
|
|
18
|
+
"wave": { "type": "integer" },
|
|
19
|
+
"roots": { "type": "array", "items": { "type": "string" }, "description": "The wave's roots; for a refused or denied wave, the roots that moved or were denied; for a failed one, the roots that failed." },
|
|
20
|
+
"run_url": { "type": "string" },
|
|
21
|
+
"report_url": { "type": "string" },
|
|
22
|
+
"outcome": { "$ref": "#/$defs/outcome" }
|
|
23
|
+
},
|
|
24
|
+
"$defs": {
|
|
25
|
+
"outcome": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"description": "terragucci.outcome/v1, as stage tf-apply wrote it to TG_OUTCOME_JSON.",
|
|
28
|
+
"required": ["schema", "status", "exit", "wave", "roots"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"schema": { "const": "terragucci.outcome/v1" },
|
|
31
|
+
"status": { "enum": ["applied", "waiting", "refused", "failed"] },
|
|
32
|
+
"exit": { "type": "integer" },
|
|
33
|
+
"wave": { "type": "integer" },
|
|
34
|
+
"roots": { "type": "array", "items": { "type": "string" } },
|
|
35
|
+
"line": { "type": "string" },
|
|
36
|
+
"set_digest": { "type": "string" },
|
|
37
|
+
"gate": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"required": ["name", "branch", "path"],
|
|
40
|
+
"properties": { "name": { "type": "string" }, "branch": { "type": "string" }, "path": { "type": "string" } }
|
|
41
|
+
},
|
|
42
|
+
"approval": { "enum": ["not-requested", "waiting", "approved", "not-required"] },
|
|
43
|
+
"approval_mode": { "enum": ["ledger", "pr-review", "sealed"] },
|
|
44
|
+
"approve_command": { "type": "string" },
|
|
45
|
+
"waiting_since": { "type": "string" },
|
|
46
|
+
"review": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"required": ["pull_request", "url"],
|
|
49
|
+
"properties": { "pull_request": { "type": "integer" }, "url": { "type": "string" } }
|
|
50
|
+
},
|
|
51
|
+
"refused": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"required": ["reason", "roots"],
|
|
54
|
+
"properties": {
|
|
55
|
+
"reason": { "enum": ["approval", "review", "override", "policy"] },
|
|
56
|
+
"approved": { "type": "string" },
|
|
57
|
+
"by": { "type": "string" },
|
|
58
|
+
"roots": { "type": "array", "items": { "type": "string" } }
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"policy_denied": { "type": "array", "items": { "type": "string" } },
|
|
62
|
+
"failed_roots": { "type": "array", "items": { "type": "string" } }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|