Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
python-version: "3.12"
- name: Verify release allowlist and hashes
run: python scripts/check_release_bundle.py
- name: Verify unified execute request contract
run: python scripts/check_execute_contract.py
- name: Run setup tests
run: python -m unittest discover -s keel-setup/tests -p 'test_*.py'
- name: Run policy tests
Expand Down
19 changes: 11 additions & 8 deletions SHA256SUMS
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
740fe7b07095e90a37f141e2141856cd83bbe8021571078c331ffc3614cb1250 .github/workflows/ci.yml
c25cb1fbeee655efde2fa1b12af630e6cf5657a5717f2ce923affbbbf7008da5 .github/workflows/ci.yml
5d87b13a525cd88e59552924d2b70e1ac4f05408ed88c1f09f2ad073657d938c .gitignore
3c0871d9b30c3e9647426b5b756be7dbfc5eee8728e6f0e0c371385de7c5f8f7 LICENSE
5fa2ec165604ae3612566968097f69d354e1722ccd5e4272793eb533a8097d23 README.md
85941406521e6d6fffcbb079283c230e2a701504b0a3a86b9e20e148efdeb0e4 SOURCE.json
2bb3f3751259b6f45ef5a899491c156c2d73e953d08919af278f056a12cc98fe SOURCE.json
9eb38e845d150019366de6cf74cf5c8b7e7a321e795f13505fb3e0788b043594 keel-policy/SKILL.md
6b449605b6b4fe6eb84f5b12befb90a57b7841d2973bbf9341cf40866e7dd81a keel-policy/examples/README.md
9a13b533704c1a37734bd6c28fc202c7acdaa8335773d55790dac50a693f8b2b keel-policy/examples/stripe-refund-approval-enterprise.json
Expand All @@ -13,16 +13,19 @@
4be41a65667952df8105e627026a921b66fc4fef19761242efabe69df0bd47cf keel-policy/reference/policy-document.schema.json
83fd6d47ded91e6b159ca3f2be5c486eb05bad7f289a591654f17141b980de99 keel-policy/scripts/validate_enforceability_report.py
322b430367e859dae341e9c225be34c6c5272c481074e7b1ae2242db527e1cbe keel-policy/tests/test_validate_enforceability_report.py
ab845c8aacdfed484bb95990f85db2d46200d65184df5a5184e24607e38e758d keel-setup/SKILL.md
f2b711de6770931e5286759c94e77b97c17d35db8d3d189c22b2f5a5e7b9bd2e keel-setup/SKILL.md
2b9c2490e921e83b83372a09e422a30f0f7ee338a2809b8e07edbd381d9eb650 keel-setup/reference/coverage.schema.json
5e9c31ef991ec9c4fc2195b4907bacbd9383d47453c6a48a0da90fb158256541 keel-setup/reference/setup-state.schema.json
b0fe7edfc7b0780853c04968ca1caf8cb94731c38e8c56981987c8e334d5c951 keel-setup/reference/unified-execute-request.contract.json
fa9e64c1fb3e6851098350d6a83c8cb185c9dea075082b12d7816b166a64f2ad keel-setup/scripts/inventory.py
640f0b4efa46a6e0382ac9dc3038bd5b79aaff2481c3fb59c5175595d84b7393 keel-setup/scripts/setup_state.py
62eea67d8892d8e5dd4552b663176c1ece9dfe636029837c7efc4e1321d8ebbd keel-setup/scripts/verify_execute.py
2786d8a6e89a36cced8af0452f2721ea4fb1b6c7b59a65e3f1ea0ac5f2837b78 keel-setup/scripts/setup_state.py
17dcf121577bd0d01d1912aabd59abb91e0c119ddccb20b3f500b662aedb3174 keel-setup/scripts/verify_execute.py
a891810ef4370ab3107627c972cfd66f18fa9554f5f2ff857312f0756c15a4f7 keel-setup/tests/test_execute_request_contract.py
3e952c3b7ebf382c39140a6a1a5e3bff9458732fe1a0ca9ea63b44206814bb80 keel-setup/tests/test_inventory.py
9d91e7ca7b0d368e3296178505f13e89c8b5f1e01771228a753256e09b6bf7f6 keel-setup/tests/test_setup_state.py
a0732181166dafc8ba7248b0698e4a5ee163f41f3779f7ea5042507747c91b00 keel-setup/tests/test_verify_execute.py
ef030ef0042f765d9d6d08795fb7570978431c4d11e6c939feea50fc9e80a0fe scripts/check_release_bundle.py
25148cb0368c3720b424573f38baf31e2baef2fb1aad9000f5f3eae3453ea374 keel-setup/tests/test_setup_state.py
2ef380a77b3eb9583e71fa99815233f7ffb6a9ab0986d82387853ea26b6117e8 keel-setup/tests/test_verify_execute.py
16b9e69e558e73eb7b32132b3382d5a7621573057fea02b101482fd9311c1bf3 scripts/check_execute_contract.py
4727d8c69971be67eeabf3662fdce88fb987c77fe9f88b507efa4a5d726ddd5e scripts/check_release_bundle.py
e0195765e2b9a31938a455fc81f93b02127f7b769948607b19a821f2bd82b2d1 shared/CONSTITUTION.md
6510e9f92c2a8fa3c40a2ca99eca06e2acaad146101c9526e06bb53f18085421 shared/feedback-report.schema.json
92b11e2380bb588b2a00be8d5eae9665b4667747fd044278a65ec2a698de7889 shared/feedback-report.template.md
Expand Down
3 changes: 2 additions & 1 deletion SOURCE.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"included_files": [
"tools/public_surface.json"
],
"source_commit": "9204f54688d3a3c6e84a3cb7c6c54c3aafd35a09",
"source_commit": "ef6b92880f0729c336b3fad85e256135c91968da",
"source_merge_commit": "165c5f308bb339d8024f9fb1d66956e0940db2e7",
"source_repository": "keelapi/keel-skills"
}
9 changes: 7 additions & 2 deletions keel-setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ python3 keel-setup/scripts/setup_state.py --repo-root . --state .keel/setup-stat

The helper validates the file against `reference/setup-state.schema.json`, refuses a file carrying a
bearer value, a credential assignment, a known credential prefix, an over-long string, or a
mapping-authority field, and reports what the return loop is due to do. Exit `1` means the state was
refused or the path is not ignored by git.
mapping-authority field, increments once, and atomically persists the validated next state only after
git confirms the exact path is ignored. It reports what the return loop is due to do. Exit `1` means
the state was refused, the ignore status could not be established, or the atomic write failed.

If the file is missing, invalid, or refused, say that continuity was lost, start at invocation 1, and
do not infer prior success from it. The count is local workflow state, not Keel evidence: it records
Expand Down Expand Up @@ -161,6 +162,10 @@ Run:
python3 keel-setup/scripts/verify_execute.py --provider PROVIDER --allow-model ALLOWED --deny-model DENIED
```

Retain the script's non-secret `request_id` and `permit_id` values for exact dashboard and Permit
matching. If either is null, report that exact correlation is unavailable; never infer it from a
nearby model name or timestamp.

The helper reads the key only from its environment. It generates an integer timestamp and a distinct
nonce inside each request attempt, sends `input.messages`, and prints only bounded classification
fields. Exit `0` means `allowed_completed` followed by `keel_denied`; exit `1` means requests completed
Expand Down
72 changes: 72 additions & 0 deletions keel-setup/reference/unified-execute-request.contract.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"contract_schema_version": "keel.public_unified_execute_request_contract.v1",
"helper_request_keys": [
"input",
"model",
"provider"
],
"schema": {
"additionalProperties": false,
"properties": {
"action_verb": {
"default": "ai.generate",
"description": "Action verb this request executes. Defaults to ai.generate for backward compatibility.",
"enum": [
"ai.generate",
"payment.execute"
],
"title": "Action Verb",
"type": "string"
},
"budget_envelope_id": {
"anyOf": [
{
"format": "uuid",
"type": "string"
},
{
"type": "null"
}
],
"description": "Optional Keel budget envelope bound to this execution. When set, the execution permit reserves against the envelope before dispatch.",
"title": "Budget Envelope Id"
},
"input": {
"additionalProperties": true,
"title": "Input",
"type": "object"
},
"model": {
"maxLength": 128,
"minLength": 1,
"title": "Model",
"type": "string"
},
"provider": {
"anyOf": [
{
"maxLength": 64,
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"title": "Provider"
}
},
"required": [
"model",
"input"
],
"title": "UnifiedExecuteRequest",
"type": "object"
},
"schema_sha256": "67beb5283aa68267eeaaa52bfcc4e7d799fe61d5e9f194445e8230de44478213",
"source_artifact": "docs/public-artifacts/openapi.json",
"source_artifact_sha256": "40f9b7ef1ad7ab38409c6b97d36ec654afc94a40f98475b6cda06b331b355db9",
"source_commit": "4ce5f5def6258004861dfaeeef512e49afc87cfd",
"source_merge_commit": "c130f73d966fce6572aa5dc8ff48164b9e9dbf15",
"source_repository": "keelapi/keel-api"
}
78 changes: 71 additions & 7 deletions keel-setup/scripts/setup_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
from __future__ import annotations

import argparse
import datetime as dt
import json
import os
import pathlib
import re
import subprocess
import sys
import tempfile
from typing import Any

ROOT = pathlib.Path(__file__).resolve().parents[2]
Expand Down Expand Up @@ -59,7 +62,9 @@
"carries a credential assignment",
),
(
re.compile(r"^(?:ks_|sk-|sk_|pk_|rk_|ghp_|gho_|xox[baprs]-)[A-Za-z0-9_\-]{8,}"),
re.compile(
r"(?<![A-Za-z0-9_])(?:ks_|sk-|sk_|pk_|rk_|ghp_|gho_|xox[baprs]-)[A-Za-z0-9_\-]{8,}"
),
"matches a known credential prefix",
),
)
Expand Down Expand Up @@ -165,12 +170,16 @@ def due_reviews(
return due


def initial_state() -> dict[str, Any]:
def _utc_now() -> str:
return dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z")


def initial_state(*, updated_at: str | None = None) -> dict[str, Any]:
return {
"schema_version": SCHEMA_VERSION,
"invocation_count": 1,
"stage": "discovery",
"updated_at": None,
"updated_at": updated_at or _utc_now(),
}


Expand All @@ -193,34 +202,70 @@ def is_git_ignored(repo_root: pathlib.Path, relative: pathlib.PurePosixPath) ->
return None


def write_state_atomically(state_path: pathlib.Path, state: dict[str, Any]) -> None:
"""Persist validated continuity without ever exposing a partial JSON file."""

failures = validate_state(state)
if failures:
raise ValueError("refusing to persist invalid local setup state: " + "; ".join(failures))

state_path.parent.mkdir(parents=True, exist_ok=True)
temporary_path: pathlib.Path | None = None
try:
with tempfile.NamedTemporaryFile(
mode="w",
encoding="utf-8",
dir=state_path.parent,
prefix=f".{state_path.name}.",
suffix=".tmp",
delete=False,
) as handle:
temporary_path = pathlib.Path(handle.name)
os.chmod(temporary_path, 0o600)
json.dump(state, handle, indent=2, sort_keys=True)
handle.write("\n")
handle.flush()
os.fsync(handle.fileno())
os.replace(temporary_path, state_path)
temporary_path = None
finally:
if temporary_path is not None:
try:
temporary_path.unlink()
except FileNotFoundError:
pass


def begin(state_path: pathlib.Path, repo_root: pathlib.Path) -> dict[str, Any]:
"""Read the state once, increment the count once, and report what is due."""
"""Read, advance, and atomically persist one local invocation."""

now = _utc_now()
continuity = "resumed"
continuity_reason: str | None = None
problems: list[str] = []
try:
raw = state_path.read_text(encoding="utf-8")
except OSError:
state = initial_state()
state = initial_state(updated_at=now)
continuity = "lost"
continuity_reason = "no local state file was readable at this path"
else:
try:
loaded = json.loads(raw)
except json.JSONDecodeError as exc:
state = initial_state()
state = initial_state(updated_at=now)
continuity = "lost"
continuity_reason = f"local state file is not valid JSON: {exc}"
else:
problems = validate_state(loaded)
if problems:
state = initial_state()
state = initial_state(updated_at=now)
continuity = "lost"
continuity_reason = "local state file was refused; see refusals"
else:
state = dict(loaded)
state["invocation_count"] = int(state["invocation_count"]) + 1
state["updated_at"] = now

stage = state.get("stage")
relative = state_path
Expand All @@ -230,6 +275,20 @@ def begin(state_path: pathlib.Path, repo_root: pathlib.Path) -> dict[str, Any]:
relative = state_path
ignored = is_git_ignored(repo_root, pathlib.PurePosixPath(pathlib.PurePath(relative).as_posix()))

state_persisted = False
persistence_error: str | None = None
if ignored is True:
try:
write_state_atomically(state_path, state)
except (OSError, ValueError) as exc:
persistence_error = f"local state was not persisted: {exc}"
else:
state_persisted = True
elif ignored is False:
persistence_error = "local state path is not ignored by git"
else:
persistence_error = "could not establish that the local state path is ignored by git"

return {
"schema_version": SCHEMA_VERSION,
"continuity": continuity,
Expand All @@ -244,6 +303,8 @@ def begin(state_path: pathlib.Path, repo_root: pathlib.Path) -> dict[str, Any]:
state.get("last_maintenance_review_invocation"),
),
"state_path_git_ignored": ignored,
"state_persisted": state_persisted,
"persistence_error": persistence_error,
"evidence_level": "unresolved",
"does_not_establish": list(DOES_NOT_ESTABLISH),
}
Expand Down Expand Up @@ -287,6 +348,9 @@ def main(argv: list[str] | None = None) -> int:
file=sys.stderr,
)
return 1
if not report["state_persisted"]:
print(report["persistence_error"] or "local state was not persisted", file=sys.stderr)
return 1
return 0


Expand Down
Loading