Packaging, rtut check, tests CI job; schemas move into the package (RBT-WP-0009-T02)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 295952@bnt-lap001 Assistant-Session: e93f64ad-516c-46eb-9666-aad8d300c477
This commit is contained in:
parent
6d3414d8b7
commit
e021fd979f
16 changed files with 163 additions and 10 deletions
|
|
@ -59,6 +59,45 @@ def _run(pk, a) -> int:
|
|||
return 1
|
||||
|
||||
|
||||
def _check(root: str) -> int:
|
||||
"""One command for CI and for humans: everything declarative in a repository must validate."""
|
||||
from . import project as J
|
||||
from .attrs import Registry
|
||||
reg = Registry([Path(root)])
|
||||
bad = 0
|
||||
print("runbooks")
|
||||
for p in reg.packs.values():
|
||||
print(f" {'ok ' if p.ok else 'FAIL'} {p.id}")
|
||||
for err in p.errors:
|
||||
print(f" - {err}")
|
||||
bad += not p.ok
|
||||
print("attribute sets")
|
||||
for sid, d in reg.sets.items():
|
||||
print(f" {'ok ' if d.ok else 'FAIL'} {sid}")
|
||||
for err in d.errors:
|
||||
print(f" - {err}")
|
||||
bad += not d.ok
|
||||
print("projects")
|
||||
for pid, d in reg.projects.items():
|
||||
errs = J.validate(reg, d)
|
||||
print(f" {'ok ' if not errs else 'FAIL'} {pid}")
|
||||
for err in errs:
|
||||
print(f" - {err}")
|
||||
bad += bool(errs)
|
||||
print("templates")
|
||||
for tid, d in reg.templates.items():
|
||||
print(f" {'ok ' if d.ok else 'FAIL'} {tid}")
|
||||
for err in d.errors:
|
||||
print(f" - {err}")
|
||||
bad += not d.ok
|
||||
total = len(reg.packs) + len(reg.sets) + len(reg.projects) + len(reg.templates)
|
||||
if not total:
|
||||
print("nothing to check", file=sys.stderr)
|
||||
return 1
|
||||
print(f"{total - bad} of {total} ok")
|
||||
return 1 if bad else 0
|
||||
|
||||
|
||||
def _project(a) -> int:
|
||||
from . import project as J
|
||||
from .attrs import Registry
|
||||
|
|
@ -135,6 +174,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||
sp = sub.add_parser("ui", help="serve the local UI on 127.0.0.1")
|
||||
sp.add_argument("roots", nargs="*", default=["."])
|
||||
sp.add_argument("--port", type=int, default=8877)
|
||||
sp = sub.add_parser("check", help="validate every pack, attribute set, project and template under a repository")
|
||||
sp.add_argument("root", nargs="?", default=".")
|
||||
sp = sub.add_parser("maturity", help="derived maturity of a pack at its current revision")
|
||||
sp.add_argument("manifest")
|
||||
sp = sub.add_parser("review", help="record that you reviewed the pack at its current revision")
|
||||
|
|
@ -172,6 +213,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||
except KeyboardInterrupt:
|
||||
pass
|
||||
return 0
|
||||
if a.cmd == "check":
|
||||
return _check(a.root)
|
||||
if a.cmd == "project":
|
||||
return _project(a)
|
||||
if a.cmd in ("maturity", "review"):
|
||||
|
|
@ -257,5 +300,10 @@ def main(argv: list[str] | None = None) -> int:
|
|||
return 0
|
||||
|
||||
|
||||
def cli() -> None:
|
||||
"""Console-script entry point (`rtut`)."""
|
||||
sys.exit(main())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ from jsonschema import Draft202012Validator
|
|||
from . import pack as P
|
||||
from .pack import SECRET_RE
|
||||
|
||||
SCHEMA_DIR = Path(__file__).resolve().parent.parent / "schema"
|
||||
SCHEMA_DIR = Path(__file__).resolve().parent / "schema"
|
||||
|
||||
|
||||
def _schema_errors(data: dict, schema_file: str) -> list[str]:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from pathlib import Path
|
|||
import yaml
|
||||
from jsonschema import Draft202012Validator
|
||||
|
||||
SCHEMA_PATH = Path(__file__).resolve().parent.parent / "schema" / "runbook-pack.schema.json"
|
||||
SCHEMA_PATH = Path(__file__).resolve().parent / "schema" / "runbook-pack.schema.json"
|
||||
PLACEHOLDER = re.compile(r"\{\{\s*([a-z][a-z0-9_]*)\s*\}\}")
|
||||
SECRET_RE = re.compile(
|
||||
r"(hvs\.[A-Za-z0-9]{8,}|s\.[A-Za-z0-9]{24}|-----BEGIN [A-Z ]*PRIVATE KEY|otpauth://)")
|
||||
|
|
|
|||
37
rtut/schema/attribute-set.schema.json
Normal file
37
rtut/schema/attribute-set.schema.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://runbook-tutorials.invalid/schema/attribute-set/v0.1",
|
||||
"title": "Attribute set",
|
||||
"type": "object",
|
||||
"required": ["spec", "id", "title", "attributes"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"spec": {"const": "attribute-set/v0.1"},
|
||||
"id": {"type": "string", "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$"},
|
||||
"title": {"type": "string", "minLength": 3},
|
||||
"extends": {"type": "array", "items": {"type": "string"}, "description": "Composed first; later entries and this set's own attributes override."},
|
||||
"attributes": {"$ref": "#/$defs/attributes"}
|
||||
},
|
||||
"$defs": {
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"propertyNames": {"pattern": "^[a-z][a-z0-9_]*$"},
|
||||
"additionalProperties": {"$ref": "#/$defs/attribute"}
|
||||
},
|
||||
"attribute": {
|
||||
"oneOf": [
|
||||
{"type": ["string", "integer", "boolean"]},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"value": {"type": ["string", "integer", "boolean"]},
|
||||
"requirement": {"enum": ["required", "optional"]},
|
||||
"note": {"type": "string"}
|
||||
},
|
||||
"minProperties": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
169
rtut/schema/project.schema.json
Normal file
169
rtut/schema/project.schema.json
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://runbook-tutorials.invalid/schema/project/v0.1",
|
||||
"title": "Project or project template",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"spec",
|
||||
"id",
|
||||
"title",
|
||||
"runbooks"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"spec": {
|
||||
"enum": [
|
||||
"project/v0.1",
|
||||
"project-template/v0.1"
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"goal": {
|
||||
"type": "string"
|
||||
},
|
||||
"environment": {
|
||||
"enum": [
|
||||
"rehearsal",
|
||||
"staging",
|
||||
"production"
|
||||
]
|
||||
},
|
||||
"template": {
|
||||
"type": "string",
|
||||
"description": "Id of the template this project was created from."
|
||||
},
|
||||
"attribute_sets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"$ref": "#/$defs/attributes"
|
||||
},
|
||||
"targets": {
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"pattern": "^[a-z][a-z0-9-]*$"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"attribute_sets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"$ref": "#/$defs/attributes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"runbooks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"pack"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"pack": {
|
||||
"type": "string"
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"after": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"attributes": {
|
||||
"$ref": "#/$defs/attributes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "What this project is, in its own words. Not inherited from a template."
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"spec": {
|
||||
"const": "project/v0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"environment"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"$defs": {
|
||||
"attributes": {
|
||||
"type": "object",
|
||||
"propertyNames": {
|
||||
"pattern": "^[a-z][a-z0-9_]*$"
|
||||
},
|
||||
"additionalProperties": {
|
||||
"$ref": "#/$defs/attribute"
|
||||
}
|
||||
},
|
||||
"attribute": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": [
|
||||
"string",
|
||||
"integer",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": [
|
||||
"string",
|
||||
"integer",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
"requirement": {
|
||||
"enum": [
|
||||
"required",
|
||||
"optional"
|
||||
]
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minProperties": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
643
rtut/schema/runbook-pack-v0.2.schema.json
Normal file
643
rtut/schema/runbook-pack-v0.2.schema.json
Normal file
|
|
@ -0,0 +1,643 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://runbook-tutorials.invalid/schema/runbook-pack/v0.2",
|
||||
"title": "Runbook pack manifest v0.2",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"spec",
|
||||
"id",
|
||||
"title",
|
||||
"owner",
|
||||
"engine"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"spec": {
|
||||
"const": "runbook-pack/v0.2"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"outcome": {
|
||||
"type": "string"
|
||||
},
|
||||
"exercise_status": {
|
||||
"type": "string",
|
||||
"deprecated": true,
|
||||
"description": "Deprecated and ignored. Maturity is derived from run history (docs/maturity-and-projects.md); old packs that still carry this field keep loading."
|
||||
},
|
||||
"engine": {
|
||||
"enum": [
|
||||
"native",
|
||||
"legacy-command"
|
||||
]
|
||||
},
|
||||
"confirm_phrase": {
|
||||
"type": "string",
|
||||
"minLength": 8,
|
||||
"description": "Typed by the operator to confirm an irreversible step."
|
||||
},
|
||||
"timeout": {
|
||||
"$ref": "#/$defs/timeout",
|
||||
"description": "Default for auto-confirm runs."
|
||||
},
|
||||
"legacy": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"command"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"framing": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Things to keep in mind; shown first; not gates."
|
||||
},
|
||||
"actors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/actor"
|
||||
}
|
||||
},
|
||||
"datapoints": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/datapoint"
|
||||
}
|
||||
},
|
||||
"stages": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/stage"
|
||||
}
|
||||
},
|
||||
"artefacts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/artefact"
|
||||
}
|
||||
},
|
||||
"ownership": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ownership"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"engine": {
|
||||
"const": "native"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"stages",
|
||||
"framing"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"engine": {
|
||||
"const": "legacy-command"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"legacy"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"$defs": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z][a-z0-9-]*$"
|
||||
},
|
||||
"dpid": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z][a-z0-9_]*$"
|
||||
},
|
||||
"timeout": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"seconds"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"seconds": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"on_timeout": {
|
||||
"enum": [
|
||||
"stop",
|
||||
"push-through"
|
||||
],
|
||||
"default": "stop"
|
||||
}
|
||||
}
|
||||
},
|
||||
"actor": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"role",
|
||||
"description"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"privileges": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"datapoint": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"label",
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/dpid"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
"string",
|
||||
"text",
|
||||
"enum",
|
||||
"path",
|
||||
"bool",
|
||||
"int"
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"type": [
|
||||
"string",
|
||||
"integer",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string"
|
||||
},
|
||||
"help": {
|
||||
"type": "string"
|
||||
},
|
||||
"dimensions": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ask_in": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"produced_by": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"confirmed_by": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"secret": {
|
||||
"const": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"check": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"done_when": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"expect": {
|
||||
"enum": [
|
||||
"manual",
|
||||
"exit-0",
|
||||
"output-contains"
|
||||
]
|
||||
},
|
||||
"contains": {
|
||||
"type": "string"
|
||||
},
|
||||
"datapoints_ok": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/dpid"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"done_when"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"datapoints_ok"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"alternative": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"verify"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"reversible": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"rollback": {
|
||||
"type": "string"
|
||||
},
|
||||
"verify": {
|
||||
"$ref": "#/$defs/check"
|
||||
},
|
||||
"recommended_when": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"idempotent": {
|
||||
"enum": [
|
||||
"idempotent",
|
||||
"non-idempotent",
|
||||
"conditional"
|
||||
]
|
||||
},
|
||||
"idempotent_note": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"step": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"actor",
|
||||
"owner"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"actor": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"reversible": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"rollback": {
|
||||
"type": "string"
|
||||
},
|
||||
"confirm_phrase": {
|
||||
"type": "string",
|
||||
"minLength": 8
|
||||
},
|
||||
"verify": {
|
||||
"$ref": "#/$defs/check"
|
||||
},
|
||||
"requires": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"uses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/dpid"
|
||||
}
|
||||
},
|
||||
"produces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"evidence": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"one_of": {
|
||||
"type": "array",
|
||||
"minItems": 2,
|
||||
"items": {
|
||||
"$ref": "#/$defs/alternative"
|
||||
}
|
||||
},
|
||||
"timeout": {
|
||||
"$ref": "#/$defs/timeout"
|
||||
},
|
||||
"downstream_risk": {
|
||||
"type": "string"
|
||||
},
|
||||
"auto_confirm": {
|
||||
"enum": [
|
||||
"allowed",
|
||||
"manual-only"
|
||||
],
|
||||
"default": "allowed"
|
||||
},
|
||||
"idempotent": {
|
||||
"enum": [
|
||||
"idempotent",
|
||||
"non-idempotent",
|
||||
"conditional"
|
||||
],
|
||||
"description": "Is re-running this step after a partial or complete earlier attempt safe? Omit if unknown. Values are words, never yes/no: YAML reads unquoted yes/no as booleans."
|
||||
},
|
||||
"idempotent_note": {
|
||||
"type": "string",
|
||||
"description": "Required when idempotent is conditional: under what condition."
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"verify"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"one_of"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"goal",
|
||||
"checks"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"goal": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"blocking": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"checks": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"$ref": "#/$defs/check"
|
||||
}
|
||||
},
|
||||
"waivable": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"by",
|
||||
"needs_reason"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"by": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"needs_reason": {
|
||||
"const": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"timeout": {
|
||||
"$ref": "#/$defs/timeout"
|
||||
},
|
||||
"downstream_risk": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"stage": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"goal"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"goal": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"framing": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"requires": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/step"
|
||||
}
|
||||
},
|
||||
"gates": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/gate"
|
||||
}
|
||||
},
|
||||
"stages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/stage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"steps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"stages"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"artefact": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"location",
|
||||
"produced_by"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"datapoint"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"datapoint": {
|
||||
"$ref": "#/$defs/dpid"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"produced_by": {
|
||||
"$ref": "#/$defs/id"
|
||||
},
|
||||
"lives_until": {
|
||||
"$ref": "#/$defs/id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ownership": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"concern",
|
||||
"owner"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"concern": {
|
||||
"type": "string"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
294
rtut/schema/runbook-pack.schema.json
Normal file
294
rtut/schema/runbook-pack.schema.json
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://runbook-tutorials.invalid/schema/runbook-pack/v0.1",
|
||||
"title": "Runbook pack manifest",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"spec",
|
||||
"id",
|
||||
"title",
|
||||
"owner",
|
||||
"engine"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"spec": {
|
||||
"const": "runbook-pack/v0.1"
|
||||
},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"description": "Repository that owns the procedure"
|
||||
},
|
||||
"outcome": {
|
||||
"type": "string"
|
||||
},
|
||||
"exercise_status": {
|
||||
"type": "string",
|
||||
"deprecated": true,
|
||||
"description": "Deprecated and ignored. Maturity is derived from run history (docs/maturity-and-projects.md); old packs that still carry this field keep loading."
|
||||
},
|
||||
"engine": {
|
||||
"enum": [
|
||||
"native",
|
||||
"legacy-command"
|
||||
]
|
||||
},
|
||||
"legacy": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"command"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"cwd": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"note": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/parameter"
|
||||
}
|
||||
},
|
||||
"prerequisites": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/prerequisite"
|
||||
}
|
||||
},
|
||||
"steps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/step"
|
||||
}
|
||||
},
|
||||
"threat_checks": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ownership": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/ownership"
|
||||
}
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"engine": {
|
||||
"const": "native"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"steps",
|
||||
"threat_checks"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"engine": {
|
||||
"const": "legacy-command"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"required": [
|
||||
"legacy"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"$defs": {
|
||||
"parameter": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"label",
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z][a-z0-9_]*$"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
"string",
|
||||
"text",
|
||||
"enum",
|
||||
"path",
|
||||
"bool",
|
||||
"int"
|
||||
]
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"type": [
|
||||
"string",
|
||||
"integer",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
"pattern": {
|
||||
"type": "string"
|
||||
},
|
||||
"help": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"const": false,
|
||||
"description": "Parameters are never secret. Secrets are entered by the operator into the tool that owns them, never into the engine."
|
||||
}
|
||||
}
|
||||
},
|
||||
"prerequisite": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"text",
|
||||
"owner"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"check": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"done_when"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"done_when": {
|
||||
"type": "string",
|
||||
"minLength": 3
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
},
|
||||
"expect": {
|
||||
"enum": [
|
||||
"manual",
|
||||
"exit-0",
|
||||
"output-contains"
|
||||
]
|
||||
},
|
||||
"contains": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"step": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"title",
|
||||
"owner",
|
||||
"verify"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z][a-z0-9-]*$"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "Template; {{param}} placeholders only"
|
||||
},
|
||||
"risk": {
|
||||
"enum": [
|
||||
"read-only",
|
||||
"changes-state",
|
||||
"attended",
|
||||
"destructive"
|
||||
],
|
||||
"default": "read-only"
|
||||
},
|
||||
"verify": {
|
||||
"$ref": "#/$defs/check"
|
||||
},
|
||||
"rollback": {
|
||||
"type": "string"
|
||||
},
|
||||
"evidence": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Names of non-secret facts recorded when the step completes"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ownership": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"concern",
|
||||
"owner"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"concern": {
|
||||
"type": "string"
|
||||
},
|
||||
"owner": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ from jsonschema import Draft202012Validator
|
|||
|
||||
from .pack import PLACEHOLDER, SECRET_RE
|
||||
|
||||
SCHEMA_PATH = Path(__file__).resolve().parent.parent / "schema" / "runbook-pack-v0.2.schema.json"
|
||||
SCHEMA_PATH = Path(__file__).resolve().parent / "schema" / "runbook-pack-v0.2.schema.json"
|
||||
MAX_DEPTH = 3
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue