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/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ jobs:
python-version: '3.11'
- run: bash scripts/bootstrap_runtime.sh
- run: ./scripts/trove-python scripts/check.py release
- name: Require a clean source checkout after release gates
run: git diff --exit-code
- name: Build and verify distribution
shell: bash
run: |
Expand Down
8 changes: 7 additions & 1 deletion scripts/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

import argparse
from dataclasses import dataclass
import os
from pathlib import Path
import subprocess
import sys
import tempfile
from typing import Sequence


ROOT = Path(__file__).resolve().parents[1]
PYTHON = ROOT / 'scripts' / 'trove-python'
AGENT_RUNTIME_OUTPUT = Path(tempfile.gettempdir()) / f'trove-agent-runtime-budgets-{os.getpid()}.json'


@dataclass(frozen=True)
Expand Down Expand Up @@ -56,7 +59,10 @@ class Check:
Check('agent-product-acceptance', (str(PYTHON), 'scripts/run_agent_product_acceptance.py')),
),
'perf': (
Check('agent-runtime', (str(PYTHON), 'scripts/benchmark_agent_runtime.py', '--rounds', '3', '--warmups', '1')),
Check('agent-runtime', (
str(PYTHON), 'scripts/benchmark_agent_runtime.py',
'--rounds', '3', '--warmups', '1', '--out', str(AGENT_RUNTIME_OUTPUT),
)),
),
}
RELEASE_ORDER = ('unit', 'contract', 'package', 'e2e', 'perf')
Expand Down
2 changes: 2 additions & 0 deletions scripts/verify_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ def verify_distribution(manifest_path: Path) -> dict[str, Any]:
or type(manifest.get('source_dirty')) is not bool
):
raise DistributionVerificationError('distribution manifest identity is invalid')
if manifest.get('source_dirty') is not False:
raise DistributionVerificationError('distribution source checkout is dirty')
for field in ('runtime_build_hash', 'catalog_hash', 'provider_package_hash', 'distribution_set_sha256'):
if not re.fullmatch(r'[0-9a-f]{64}', str(manifest.get(field) or '')):
raise DistributionVerificationError('distribution hash is invalid')
Expand Down
11 changes: 11 additions & 0 deletions tests/e2e/test_provider_package_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ def test_tampered_provider_artifact_is_rejected_before_install(self):
with self.assertRaisesRegex(DistributionVerificationError, 'artifact hash mismatch'):
verify_distribution(copied / 'distribution-manifest.json')

def test_dirty_source_manifest_is_rejected_before_install(self):
with tempfile.TemporaryDirectory() as directory:
copied = Path(directory) / 'distribution'
shutil.copytree(distribution_dir(), copied)
manifest_path = copied / 'distribution-manifest.json'
manifest = json.loads(manifest_path.read_text())
manifest['source_dirty'] = True
manifest_path.write_text(json.dumps(manifest, sort_keys=True, separators=(',', ':')) + '\n')
with self.assertRaisesRegex(DistributionVerificationError, 'source checkout is dirty'):
verify_distribution(manifest_path)


if __name__ == '__main__':
unittest.main()
6 changes: 6 additions & 0 deletions tests/test_agent_runtime_benchmark_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
)
from scripts.measure_agent_surface import estimate_json_tokens
from scripts.generate_fixture_vault import redacted_fixture_metadata
from scripts.check import ROOT as CHECK_ROOT, selected_checks
from scripts.release_gate_contracts import agent_runtime_budget_contract_valid


Expand All @@ -27,6 +28,11 @@ def test_cli_help_renders_on_supported_python_versions(self):
self.assertIn('10% p95', output.getvalue())
self.assertIn('regression gate', output.getvalue())

def test_perf_gate_writes_its_receipt_outside_the_source_checkout(self):
command = selected_checks('perf')[0].command
output = Path(command[command.index('--out') + 1]).resolve()
self.assertFalse(output.is_relative_to(CHECK_ROOT.resolve()))

def _artifact(self) -> dict:
measurements = {
name: {
Expand Down