agentic-harness 0.2.0__tar.gz
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.
- agentic_harness-0.2.0/.agent-harness.yml +17 -0
- agentic_harness-0.2.0/.github/workflows/ci.yml +59 -0
- agentic_harness-0.2.0/.github/workflows/publish.yml +71 -0
- agentic_harness-0.2.0/.gitignore +136 -0
- agentic_harness-0.2.0/.gitleaks.toml +5 -0
- agentic_harness-0.2.0/.pre-commit-config.yaml +16 -0
- agentic_harness-0.2.0/.yamllint.yml +11 -0
- agentic_harness-0.2.0/CLAUDE.md +118 -0
- agentic_harness-0.2.0/CONTRIBUTING.md +181 -0
- agentic_harness-0.2.0/LICENSE +21 -0
- agentic_harness-0.2.0/Makefile +24 -0
- agentic_harness-0.2.0/PKG-INFO +310 -0
- agentic_harness-0.2.0/PLANS.md +55 -0
- agentic_harness-0.2.0/README.md +285 -0
- agentic_harness-0.2.0/TODO.md +32 -0
- agentic_harness-0.2.0/docs/plans/2026-03-25-js-stack-and-universal-fixes.md +1804 -0
- agentic_harness-0.2.0/docs/plans/2026-03-25-mvp.md +830 -0
- agentic_harness-0.2.0/docs/plans/2026-03-25-refactor-stacks.md +128 -0
- agentic_harness-0.2.0/docs/plans/2026-03-26-full-restructure.md +358 -0
- agentic_harness-0.2.0/docs/plans/2026-03-26-init-as-harness-linter.md +271 -0
- agentic_harness-0.2.0/docs/plans/2026-03-26-init-setup-checks.md +1376 -0
- agentic_harness-0.2.0/docs/plans/2026-03-26-v02-cli-simplification.md +410 -0
- agentic_harness-0.2.0/docs/plans/2026-03-26-v1-vision-declarative-harness.md +85 -0
- agentic_harness-0.2.0/docs/superpowers/plans/2026-03-26-gitignore-enforcement.md +848 -0
- agentic_harness-0.2.0/docs/superpowers/plans/2026-03-27-claudemd-audit-and-security-audit.md +2015 -0
- agentic_harness-0.2.0/docs/superpowers/plans/2026-03-29-i0194-dockerfile-discovery-and-conftest-exceptions.md +1658 -0
- agentic_harness-0.2.0/docs/superpowers/plans/2026-03-29-skill-product-experience.md +714 -0
- agentic_harness-0.2.0/docs/superpowers/specs/2026-03-26-gitignore-enforcement-design.md +107 -0
- agentic_harness-0.2.0/docs/superpowers/specs/2026-03-29-i0194-dockerfile-discovery-and-conftest-exceptions.md +125 -0
- agentic_harness-0.2.0/pyproject.toml +48 -0
- agentic_harness-0.2.0/scripts/update-gitignore-templates.sh +20 -0
- agentic_harness-0.2.0/skills/agent-harness/SKILL.md +358 -0
- agentic_harness-0.2.0/skills/agent-harness/docker-guidance.md +171 -0
- agentic_harness-0.2.0/skills/agent-harness/monorepo-guidance.md +19 -0
- agentic_harness-0.2.0/skills/agent-harness/python-guidance.md +35 -0
- agentic_harness-0.2.0/src/agent_harness/__init__.py +6 -0
- agentic_harness-0.2.0/src/agent_harness/cli.py +179 -0
- agentic_harness-0.2.0/src/agent_harness/config.py +57 -0
- agentic_harness-0.2.0/src/agent_harness/conftest.py +51 -0
- agentic_harness-0.2.0/src/agent_harness/detect.py +54 -0
- agentic_harness-0.2.0/src/agent_harness/exclusions.py +64 -0
- agentic_harness-0.2.0/src/agent_harness/fix.py +36 -0
- agentic_harness-0.2.0/src/agent_harness/git_files.py +75 -0
- agentic_harness-0.2.0/src/agent_harness/init/__init__.py +0 -0
- agentic_harness-0.2.0/src/agent_harness/init/diagnostic.py +69 -0
- agentic_harness-0.2.0/src/agent_harness/init/scaffold.py +169 -0
- agentic_harness-0.2.0/src/agent_harness/init/templates.py +141 -0
- agentic_harness-0.2.0/src/agent_harness/lint.py +38 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/configs.rego +33 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/configs_test.rego +23 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/escaping.rego +72 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/escaping_test.rego +46 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/hostname.rego +63 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/hostname_test.rego +69 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/images.rego +108 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/images_test.rego +72 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/services.rego +95 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/services_test.rego +75 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/volumes.rego +58 -0
- agentic_harness-0.2.0/src/agent_harness/policies/compose/volumes_test.rego +39 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/base_image.rego +45 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/base_image_test.rego +44 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/cache.rego +48 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/cache_test.rego +44 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/healthcheck.rego +38 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/healthcheck_test.rego +33 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/layers.rego +100 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/layers_test.rego +55 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/secrets.rego +88 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/secrets_test.rego +47 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/user.rego +39 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dockerfile/user_test.rego +33 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dokploy/traefik.rego +72 -0
- agentic_harness-0.2.0/src/agent_harness/policies/dokploy/traefik_test.rego +90 -0
- agentic_harness-0.2.0/src/agent_harness/policies/gitignore/secrets.rego +64 -0
- agentic_harness-0.2.0/src/agent_harness/policies/gitignore/secrets_test.rego +62 -0
- agentic_harness-0.2.0/src/agent_harness/policies/javascript/package.rego +61 -0
- agentic_harness-0.2.0/src/agent_harness/policies/javascript/package_test.rego +66 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/coverage.rego +43 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/coverage_test.rego +50 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/pytest.rego +56 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/pytest_test.rego +41 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/ruff.rego +69 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/ruff_test.rego +47 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/test_isolation.rego +31 -0
- agentic_harness-0.2.0/src/agent_harness/policies/python/test_isolation_test.rego +20 -0
- agentic_harness-0.2.0/src/agent_harness/preset.py +47 -0
- agentic_harness-0.2.0/src/agent_harness/presets/__init__.py +1 -0
- agentic_harness-0.2.0/src/agent_harness/presets/docker/__init__.py +60 -0
- agentic_harness-0.2.0/src/agent_harness/presets/docker/conftest_compose_check.py +51 -0
- agentic_harness-0.2.0/src/agent_harness/presets/docker/conftest_dockerfile_check.py +76 -0
- agentic_harness-0.2.0/src/agent_harness/presets/docker/detect.py +20 -0
- agentic_harness-0.2.0/src/agent_harness/presets/docker/hadolint_check.py +51 -0
- agentic_harness-0.2.0/src/agent_harness/presets/docker/templates.py +46 -0
- agentic_harness-0.2.0/src/agent_harness/presets/dokploy/__init__.py +38 -0
- agentic_harness-0.2.0/src/agent_harness/presets/dokploy/conftest_dokploy_check.py +51 -0
- agentic_harness-0.2.0/src/agent_harness/presets/dokploy/detect.py +16 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/__init__.py +56 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/biome_check.py +58 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/conftest_package_check.py +34 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/detect.py +10 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/fix.py +23 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/templates.py +39 -0
- agentic_harness-0.2.0/src/agent_harness/presets/javascript/type_check.py +75 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/__init__.py +51 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/conftest_check.py +18 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/detect.py +10 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/fix.py +36 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/ruff_check.py +47 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/setup_check.py +168 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/templates.py +225 -0
- agentic_harness-0.2.0/src/agent_harness/presets/python/ty_check.py +32 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/__init__.py +96 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/claudemd_setup.py +64 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/conftest_gitignore_check.py +40 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/conftest_json_check.py +91 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/file_length_check.py +85 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/gitignore_setup.py +167 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/gitignore_tracked_check.py +59 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/gitignore_tracked_fix.py +37 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/precommit_check.py +82 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/templates.py +49 -0
- agentic_harness-0.2.0/src/agent_harness/presets/universal/yamllint_check.py +95 -0
- agentic_harness-0.2.0/src/agent_harness/registry.py +10 -0
- agentic_harness-0.2.0/src/agent_harness/runner.py +73 -0
- agentic_harness-0.2.0/src/agent_harness/security/__init__.py +0 -0
- agentic_harness-0.2.0/src/agent_harness/security/audit.py +36 -0
- agentic_harness-0.2.0/src/agent_harness/security/config.py +48 -0
- agentic_harness-0.2.0/src/agent_harness/security/display.py +60 -0
- agentic_harness-0.2.0/src/agent_harness/security/gitleaks_scanner.py +100 -0
- agentic_harness-0.2.0/src/agent_harness/security/models.py +76 -0
- agentic_harness-0.2.0/src/agent_harness/security/osv_scanner.py +150 -0
- agentic_harness-0.2.0/src/agent_harness/setup_check.py +21 -0
- agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Linux.gitignore +16 -0
- agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Node.gitignore +144 -0
- agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Python.gitignore +216 -0
- agentic_harness-0.2.0/src/agent_harness/templates/gitignore/SOURCE.md +6 -0
- agentic_harness-0.2.0/src/agent_harness/templates/gitignore/Windows.gitignore +24 -0
- agentic_harness-0.2.0/src/agent_harness/templates/gitignore/macOS.gitignore +25 -0
- agentic_harness-0.2.0/src/agent_harness/workspace.py +13 -0
- agentic_harness-0.2.0/tests/__init__.py +0 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_bare_dollar.yml +13 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_build_directive.yml +6 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_mutable_tag_no_pull.yml +11 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_no_healthcheck.yml +6 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_no_hostname.yml +14 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_no_restart.yml +10 -0
- agentic_harness-0.2.0/tests/fixtures/compose/bad_port_binding.yml +13 -0
- agentic_harness-0.2.0/tests/fixtures/compose/good_escaped_dollar.yml +14 -0
- agentic_harness-0.2.0/tests/fixtures/compose/good_full.yml +41 -0
- agentic_harness-0.2.0/tests/fixtures/compose/good_hostname.yml +15 -0
- agentic_harness-0.2.0/tests/fixtures/compose/good_one_shot_exempt.yml +18 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_alpine_node.Dockerfile +9 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_alpine_python.Dockerfile +9 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_copy_before_deps.Dockerfile +8 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_no_cache_mount.Dockerfile +9 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_no_healthcheck.Dockerfile +8 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_no_user.Dockerfile +8 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_secret_in_arg.Dockerfile +10 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_secret_in_env.Dockerfile +10 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/bad_src_before_deps.Dockerfile +9 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/good_alpine_go.Dockerfile +10 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/good_cache_mount.Dockerfile +9 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/good_complete.Dockerfile +14 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/good_layer_order.Dockerfile +10 -0
- agentic_harness-0.2.0/tests/fixtures/dockerfile/good_multistage_copy.Dockerfile +14 -0
- agentic_harness-0.2.0/tests/presets/__init__.py +0 -0
- agentic_harness-0.2.0/tests/presets/docker/__init__.py +0 -0
- agentic_harness-0.2.0/tests/presets/docker/test_conftest_compose_check.py +7 -0
- agentic_harness-0.2.0/tests/presets/docker/test_conftest_dockerfile_check.py +89 -0
- agentic_harness-0.2.0/tests/presets/docker/test_find_dockerfiles.py +51 -0
- agentic_harness-0.2.0/tests/presets/docker/test_hadolint_check.py +8 -0
- agentic_harness-0.2.0/tests/presets/dokploy/__init__.py +0 -0
- agentic_harness-0.2.0/tests/presets/dokploy/test_conftest_dokploy_check.py +7 -0
- agentic_harness-0.2.0/tests/presets/dokploy/test_detect.py +41 -0
- agentic_harness-0.2.0/tests/presets/javascript/__init__.py +0 -0
- agentic_harness-0.2.0/tests/presets/javascript/test_biome_check.py +46 -0
- agentic_harness-0.2.0/tests/presets/javascript/test_conftest_package_check.py +7 -0
- agentic_harness-0.2.0/tests/presets/javascript/test_detect.py +20 -0
- agentic_harness-0.2.0/tests/presets/javascript/test_type_check.py +49 -0
- agentic_harness-0.2.0/tests/presets/python/__init__.py +0 -0
- agentic_harness-0.2.0/tests/presets/python/test_detect.py +15 -0
- agentic_harness-0.2.0/tests/presets/python/test_ruff_check.py +8 -0
- agentic_harness-0.2.0/tests/presets/python/test_setup.py +163 -0
- agentic_harness-0.2.0/tests/presets/universal/__init__.py +0 -0
- agentic_harness-0.2.0/tests/presets/universal/conftest.py +20 -0
- agentic_harness-0.2.0/tests/presets/universal/test_claudemd_setup.py +52 -0
- agentic_harness-0.2.0/tests/presets/universal/test_conftest_gitignore_check.py +32 -0
- agentic_harness-0.2.0/tests/presets/universal/test_conftest_json_check.py +51 -0
- agentic_harness-0.2.0/tests/presets/universal/test_file_length_check.py +50 -0
- agentic_harness-0.2.0/tests/presets/universal/test_gitignore_setup.py +119 -0
- agentic_harness-0.2.0/tests/presets/universal/test_gitignore_tracked_check.py +103 -0
- agentic_harness-0.2.0/tests/presets/universal/test_gitignore_tracked_fix.py +52 -0
- agentic_harness-0.2.0/tests/presets/universal/test_precommit_check.py +101 -0
- agentic_harness-0.2.0/tests/presets/universal/test_yamllint_check.py +51 -0
- agentic_harness-0.2.0/tests/security/__init__.py +0 -0
- agentic_harness-0.2.0/tests/security/test_audit.py +119 -0
- agentic_harness-0.2.0/tests/security/test_display.py +52 -0
- agentic_harness-0.2.0/tests/security/test_gitleaks_scanner.py +90 -0
- agentic_harness-0.2.0/tests/security/test_models.py +126 -0
- agentic_harness-0.2.0/tests/security/test_osv_scanner.py +170 -0
- agentic_harness-0.2.0/tests/security/test_security_config.py +71 -0
- agentic_harness-0.2.0/tests/test_cli.py +40 -0
- agentic_harness-0.2.0/tests/test_config.py +92 -0
- agentic_harness-0.2.0/tests/test_detect.py +142 -0
- agentic_harness-0.2.0/tests/test_diagnostic.py +108 -0
- agentic_harness-0.2.0/tests/test_exclusions.py +33 -0
- agentic_harness-0.2.0/tests/test_git_files.py +95 -0
- agentic_harness-0.2.0/tests/test_init.py +97 -0
- agentic_harness-0.2.0/tests/test_lint_all.py +35 -0
- agentic_harness-0.2.0/tests/test_runner.py +18 -0
- agentic_harness-0.2.0/tests/test_setup.py +39 -0
- agentic_harness-0.2.0/tests/test_workspace.py +48 -0
- agentic_harness-0.2.0/uv.lock +211 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# AI Harness configuration
|
|
2
|
+
# Detected stacks: python
|
|
3
|
+
stacks: [python]
|
|
4
|
+
|
|
5
|
+
# exclude:
|
|
6
|
+
# - _archive/
|
|
7
|
+
# - vendor/
|
|
8
|
+
|
|
9
|
+
# python:
|
|
10
|
+
# coverage_threshold: 95
|
|
11
|
+
# line_length: 140
|
|
12
|
+
|
|
13
|
+
# javascript:
|
|
14
|
+
# coverage_threshold: 80
|
|
15
|
+
|
|
16
|
+
# docker:
|
|
17
|
+
# own_image_prefix: "ghcr.io/myorg/"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [master]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: astral-sh/setup-uv@v4
|
|
15
|
+
with:
|
|
16
|
+
version: "latest"
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install tools
|
|
23
|
+
run: |
|
|
24
|
+
uv sync
|
|
25
|
+
uv tool install -e .
|
|
26
|
+
|
|
27
|
+
# Install external tools
|
|
28
|
+
# conftest
|
|
29
|
+
CONFTEST_VERSION=0.56.0
|
|
30
|
+
curl -sL "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz" | tar xz -C /usr/local/bin conftest
|
|
31
|
+
|
|
32
|
+
# hadolint
|
|
33
|
+
HADOLINT_VERSION=2.12.0
|
|
34
|
+
curl -sL "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-x86_64" -o /usr/local/bin/hadolint
|
|
35
|
+
chmod +x /usr/local/bin/hadolint
|
|
36
|
+
|
|
37
|
+
# yamllint
|
|
38
|
+
uv tool install yamllint
|
|
39
|
+
|
|
40
|
+
# gitleaks
|
|
41
|
+
GITLEAKS_VERSION=8.21.2
|
|
42
|
+
curl -sL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar xz -C /usr/local/bin gitleaks
|
|
43
|
+
|
|
44
|
+
# osv-scanner
|
|
45
|
+
OSV_VERSION=1.9.1
|
|
46
|
+
curl -sL "https://github.com/google/osv-scanner/releases/download/v${OSV_VERSION}/osv-scanner_linux_amd64" -o /usr/local/bin/osv-scanner
|
|
47
|
+
chmod +x /usr/local/bin/osv-scanner
|
|
48
|
+
|
|
49
|
+
- name: Lint
|
|
50
|
+
run: agent-harness lint
|
|
51
|
+
|
|
52
|
+
- name: Test
|
|
53
|
+
run: uv run pytest tests/ -v
|
|
54
|
+
|
|
55
|
+
- name: Rego tests
|
|
56
|
+
run: conftest verify -p src/agent_harness/policies/ --no-color
|
|
57
|
+
|
|
58
|
+
- name: Security audit
|
|
59
|
+
run: agent-harness security-audit
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
check:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: astral-sh/setup-uv@v4
|
|
15
|
+
with:
|
|
16
|
+
version: "latest"
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install tools
|
|
23
|
+
run: |
|
|
24
|
+
uv sync
|
|
25
|
+
uv tool install -e .
|
|
26
|
+
|
|
27
|
+
CONFTEST_VERSION=0.56.0
|
|
28
|
+
curl -sL "https://github.com/open-policy-agent/conftest/releases/download/v${CONFTEST_VERSION}/conftest_${CONFTEST_VERSION}_Linux_x86_64.tar.gz" | tar xz -C /usr/local/bin conftest
|
|
29
|
+
|
|
30
|
+
HADOLINT_VERSION=2.12.0
|
|
31
|
+
curl -sL "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-x86_64" -o /usr/local/bin/hadolint
|
|
32
|
+
chmod +x /usr/local/bin/hadolint
|
|
33
|
+
|
|
34
|
+
uv tool install yamllint
|
|
35
|
+
|
|
36
|
+
GITLEAKS_VERSION=8.21.2
|
|
37
|
+
curl -sL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" | tar xz -C /usr/local/bin gitleaks
|
|
38
|
+
|
|
39
|
+
OSV_VERSION=1.9.1
|
|
40
|
+
curl -sL "https://github.com/google/osv-scanner/releases/download/v${OSV_VERSION}/osv-scanner_linux_amd64" -o /usr/local/bin/osv-scanner
|
|
41
|
+
chmod +x /usr/local/bin/osv-scanner
|
|
42
|
+
|
|
43
|
+
- name: Full quality gate
|
|
44
|
+
run: |
|
|
45
|
+
agent-harness lint
|
|
46
|
+
uv run pytest tests/ -v
|
|
47
|
+
conftest verify -p src/agent_harness/policies/ --no-color
|
|
48
|
+
agent-harness security-audit
|
|
49
|
+
|
|
50
|
+
publish:
|
|
51
|
+
needs: check
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
environment: pypi
|
|
54
|
+
permissions:
|
|
55
|
+
id-token: write
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@v4
|
|
58
|
+
|
|
59
|
+
- uses: astral-sh/setup-uv@v4
|
|
60
|
+
with:
|
|
61
|
+
version: "latest"
|
|
62
|
+
|
|
63
|
+
- uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: "3.12"
|
|
66
|
+
|
|
67
|
+
- name: Build
|
|
68
|
+
run: uv build
|
|
69
|
+
|
|
70
|
+
- name: Publish to PyPI
|
|
71
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
.env
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.venv/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.coverage
|
|
9
|
+
coverage.xml
|
|
10
|
+
.worktrees/
|
|
11
|
+
.DS_Store
|
|
12
|
+
|
|
13
|
+
# Added by agent-harness
|
|
14
|
+
$RECYCLE.BIN/
|
|
15
|
+
*$py.class
|
|
16
|
+
*.aof
|
|
17
|
+
*.cab
|
|
18
|
+
*.cover
|
|
19
|
+
*.egg
|
|
20
|
+
*.lnk
|
|
21
|
+
*.log
|
|
22
|
+
*.manifest
|
|
23
|
+
*.mo
|
|
24
|
+
*.msi
|
|
25
|
+
*.msix
|
|
26
|
+
*.msm
|
|
27
|
+
*.msp
|
|
28
|
+
*.pid
|
|
29
|
+
*.pot
|
|
30
|
+
*.py.cover
|
|
31
|
+
*.py[codz]
|
|
32
|
+
*.rdb
|
|
33
|
+
*.sage.py
|
|
34
|
+
*.so
|
|
35
|
+
*.spec
|
|
36
|
+
*.stackdump
|
|
37
|
+
*~
|
|
38
|
+
.AppleDB
|
|
39
|
+
.AppleDesktop
|
|
40
|
+
.AppleDouble
|
|
41
|
+
.DocumentRevisions-V100
|
|
42
|
+
.LSOverride
|
|
43
|
+
.Python
|
|
44
|
+
.Spotlight-V100
|
|
45
|
+
.TemporaryItems
|
|
46
|
+
.Trash-*
|
|
47
|
+
.Trashes
|
|
48
|
+
.VolumeIcon.icns
|
|
49
|
+
._*
|
|
50
|
+
.abstra/
|
|
51
|
+
.apdisk
|
|
52
|
+
.cache
|
|
53
|
+
.com.apple.timemachine.donotpresent
|
|
54
|
+
.coverage.*
|
|
55
|
+
.directory
|
|
56
|
+
.dmypy.json
|
|
57
|
+
.eggs/
|
|
58
|
+
.envrc
|
|
59
|
+
.fseventsd
|
|
60
|
+
.fuse_hidden*
|
|
61
|
+
.hypothesis/
|
|
62
|
+
.installed.cfg
|
|
63
|
+
.ipynb_checkpoints
|
|
64
|
+
.mypy_cache/
|
|
65
|
+
.nfs*
|
|
66
|
+
.nox/
|
|
67
|
+
.pdm-build/
|
|
68
|
+
.pdm-python
|
|
69
|
+
.pixi
|
|
70
|
+
.pybuilder/
|
|
71
|
+
.pypirc
|
|
72
|
+
.pyre/
|
|
73
|
+
.pytest_cache/
|
|
74
|
+
.pytype/
|
|
75
|
+
.ropeproject
|
|
76
|
+
.ruff_cache/
|
|
77
|
+
.scrapy
|
|
78
|
+
.spyderproject
|
|
79
|
+
.spyproject
|
|
80
|
+
.streamlit/secrets.toml
|
|
81
|
+
.tox/
|
|
82
|
+
.venv
|
|
83
|
+
.webassets-cache
|
|
84
|
+
/site
|
|
85
|
+
ENV/
|
|
86
|
+
Icon[
|
|
87
|
+
MANIFEST
|
|
88
|
+
Network Trash Folder
|
|
89
|
+
Temporary Items
|
|
90
|
+
Thumbs.db
|
|
91
|
+
Thumbs.db:encryptable
|
|
92
|
+
[Dd]esktop.ini
|
|
93
|
+
]
|
|
94
|
+
__MACOSX/
|
|
95
|
+
__marimo__/
|
|
96
|
+
__pypackages__/
|
|
97
|
+
activemq-data/
|
|
98
|
+
celerybeat-schedule
|
|
99
|
+
celerybeat.pid
|
|
100
|
+
cover/
|
|
101
|
+
cython_debug/
|
|
102
|
+
db.sqlite3
|
|
103
|
+
db.sqlite3-journal
|
|
104
|
+
develop-eggs/
|
|
105
|
+
dmypy.json
|
|
106
|
+
docs/_build/
|
|
107
|
+
downloads/
|
|
108
|
+
eggs/
|
|
109
|
+
ehthumbs.db
|
|
110
|
+
ehthumbs_vista.db
|
|
111
|
+
env.bak/
|
|
112
|
+
env/
|
|
113
|
+
htmlcov/
|
|
114
|
+
instance/
|
|
115
|
+
ipython_config.py
|
|
116
|
+
lib/
|
|
117
|
+
lib64/
|
|
118
|
+
local_settings.py
|
|
119
|
+
marimo/_lsp/
|
|
120
|
+
marimo/_static/
|
|
121
|
+
mnesia/
|
|
122
|
+
nohup.out
|
|
123
|
+
nosetests.xml
|
|
124
|
+
parts/
|
|
125
|
+
pip-delete-this-directory.txt
|
|
126
|
+
pip-log.txt
|
|
127
|
+
profile_default/
|
|
128
|
+
rabbitmq-data/
|
|
129
|
+
rabbitmq/
|
|
130
|
+
sdist/
|
|
131
|
+
share/python-wheels/
|
|
132
|
+
target/
|
|
133
|
+
var/
|
|
134
|
+
venv.bak/
|
|
135
|
+
venv/
|
|
136
|
+
wheels/
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: local
|
|
3
|
+
hooks:
|
|
4
|
+
- id: harness-fix
|
|
5
|
+
name: auto-fix
|
|
6
|
+
entry: agent-harness fix
|
|
7
|
+
language: system
|
|
8
|
+
pass_filenames: false
|
|
9
|
+
always_run: true
|
|
10
|
+
|
|
11
|
+
- id: harness-lint
|
|
12
|
+
name: agent-harness lint
|
|
13
|
+
entry: agent-harness lint
|
|
14
|
+
language: system
|
|
15
|
+
pass_filenames: false
|
|
16
|
+
always_run: true
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# agent-harness
|
|
2
|
+
|
|
3
|
+
Deterministic quality gates for AI-assisted development. This project IS a harness — it enforces its own rules.
|
|
4
|
+
|
|
5
|
+
## Dev Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
make lint # agent-harness lint (runs all checks)
|
|
9
|
+
make fix # agent-harness fix (auto-fix, then lint)
|
|
10
|
+
make test # pytest + conftest verify (all tests)
|
|
11
|
+
make security-audit # check deps + secrets in working dir (fast)
|
|
12
|
+
make check # full gate: lint + test + security-audit
|
|
13
|
+
agent-harness security-audit-history # deep scan git history for leaked secrets (run once)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Install dev deps: `uv sync`
|
|
17
|
+
|
|
18
|
+
## Workflow
|
|
19
|
+
|
|
20
|
+
Pre-commit hooks run `agent-harness fix` and `agent-harness lint` automatically on every commit.
|
|
21
|
+
Before declaring work done, always run `make check` — it's the full quality gate.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uv tool install -e . # install CLI globally from source
|
|
28
|
+
uv sync # install dev deps (ruff, ty, pytest)
|
|
29
|
+
agent-harness lint # verify everything passes
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
src/agent_harness/
|
|
36
|
+
cli.py — Click CLI: detect, init, lint, fix, security-audit (thin — delegates)
|
|
37
|
+
config.py — Dict-based config from .agent-harness.yml
|
|
38
|
+
runner.py — run_check(), CheckResult, tool_available()
|
|
39
|
+
conftest.py — Shared conftest runner (used by all Rego checks)
|
|
40
|
+
exclusions.py — File exclusion patterns
|
|
41
|
+
workspace.py — Discover subproject roots
|
|
42
|
+
preset.py — Preset base class + ToolInfo/PresetInfo
|
|
43
|
+
registry.py — Explicit preset registration (PRESETS + UNIVERSAL)
|
|
44
|
+
detect.py — Thin orchestrator: for preset in PRESETS: preset.detect()
|
|
45
|
+
lint.py — Thin orchestrator: for preset in PRESETS: preset.run_checks()
|
|
46
|
+
fix.py — Thin orchestrator: for preset in PRESETS: preset.run_fix()
|
|
47
|
+
init/ — Scaffolding (reads preset.get_info())
|
|
48
|
+
presets/
|
|
49
|
+
universal/ — Always runs: yamllint, gitignore, JSON, file length
|
|
50
|
+
python/ — ruff, ty, conftest on pyproject.toml
|
|
51
|
+
javascript/ — Biome, framework type checker, conftest on package.json
|
|
52
|
+
docker/ — hadolint, conftest on Dockerfile + compose
|
|
53
|
+
dokploy/ — conftest for Traefik/Dokploy conventions
|
|
54
|
+
security/ — osv-scanner + gitleaks runners, policy engine, CVE ignore
|
|
55
|
+
policies/ — Rego policies (bundled). Each has WHAT/WHY/FIX.
|
|
56
|
+
|
|
57
|
+
skills/agent-harness/ — Claude Code plugin (SKILL.md + guidance docs)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Adding a new preset
|
|
61
|
+
|
|
62
|
+
1. Create `presets/<name>/` with `__init__.py` implementing `Preset`
|
|
63
|
+
2. Add individual check files (one per tool)
|
|
64
|
+
3. Add `<Name>Preset()` to `registry.py`
|
|
65
|
+
4. Add Rego policies to `policies/<name>/` if needed
|
|
66
|
+
|
|
67
|
+
## Conventions
|
|
68
|
+
|
|
69
|
+
- Each preset implements: `detect()`, `run_checks()`, `run_fix()`, `run_setup()`, `get_info()`
|
|
70
|
+
- One check per file, with WHAT/WHY/WITHOUT IT/FIX/REQUIRES docstring
|
|
71
|
+
- One Rego policy per file, with `_test.rego` sibling
|
|
72
|
+
- All conftest checks use shared `conftest.py` (never local `_run_conftest`)
|
|
73
|
+
- Tool fallback: `shutil.which()` → `uv run` (Python) or `npx` (JS)
|
|
74
|
+
|
|
75
|
+
## Policy Design Strategy
|
|
76
|
+
|
|
77
|
+
Every check belongs in exactly one place. The boundary:
|
|
78
|
+
|
|
79
|
+
**"Would any reasonable person agree this is broken?"**
|
|
80
|
+
- YES → lint (Rego `deny` rule in `policies/`)
|
|
81
|
+
- Debatable → init (Python setup check in `presets/*/setup.py`)
|
|
82
|
+
|
|
83
|
+
### Lint (Rego, every commit)
|
|
84
|
+
- Only `deny` rules. No `warn`.
|
|
85
|
+
- Checks that gates EXIST and aren't objectively broken.
|
|
86
|
+
- Examples: `--strict-markers` missing, `--cov-fail-under` missing, threshold < 30%
|
|
87
|
+
|
|
88
|
+
### Init (Python, on-demand)
|
|
89
|
+
- `SetupIssue` with severity `critical` (fixable) or `recommendation`.
|
|
90
|
+
- Checks configuration QUALITY. Can auto-fix.
|
|
91
|
+
- Examples: threshold = 50% (recommend 90-95%), missing `-v` flag
|
|
92
|
+
|
|
93
|
+
### Skill (agent guidance, context-dependent)
|
|
94
|
+
- Actions that require judgment, context, or reading intent.
|
|
95
|
+
- The skill tells the agent WHAT to evaluate and WHY, but the agent decides HOW.
|
|
96
|
+
- Examples: reorganize .gitignore (needs to know which patterns are stale),
|
|
97
|
+
audit CLAUDE.md (needs project context), replace redundant Makefile targets
|
|
98
|
+
(needs to understand what the target was for)
|
|
99
|
+
|
|
100
|
+
### The boundary: init does, skill guides
|
|
101
|
+
Init must be safe to run blindly (`--apply` never breaks a project).
|
|
102
|
+
If an action could destroy user intent (rewriting .gitignore, editing CLAUDE.md),
|
|
103
|
+
init does the safe subset (deduplicated append) and the skill guides the agent
|
|
104
|
+
to do the rest (full cleanup, reorganization).
|
|
105
|
+
|
|
106
|
+
### Same topic, all three places
|
|
107
|
+
A single topic (e.g., .gitignore completeness) can have:
|
|
108
|
+
- Lint Rego: "are generated files tracked?" (objectively broken)
|
|
109
|
+
- Init Python: "append missing patterns grouped by category" (safe, mechanical)
|
|
110
|
+
- Skill: "review and clean up the full .gitignore — remove stale patterns, reorganize" (judgment)
|
|
111
|
+
|
|
112
|
+
## Never
|
|
113
|
+
|
|
114
|
+
- Never embed tool binaries — require them installed externally
|
|
115
|
+
- Never run checks in Docker — must be <500ms local
|
|
116
|
+
- Never duplicate `_run_conftest` — use `agent_harness.conftest.run_conftest()`
|
|
117
|
+
- Never truncate lint/test output with `| tail` or `| head` — output is already optimized
|
|
118
|
+
- Never skip `make check` before declaring a task complete
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# Contributing to Agent Harness
|
|
2
|
+
|
|
3
|
+
Agent Harness enforces its own rules. We use agent-harness to develop agent-harness.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/agentic-eng/agent-harness
|
|
9
|
+
cd agent-harness
|
|
10
|
+
uv sync # install dev deps
|
|
11
|
+
uv tool install -e . # install CLI globally from source
|
|
12
|
+
agent-harness lint # verify everything passes
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quality gate
|
|
16
|
+
|
|
17
|
+
Before every commit (enforced by pre-commit hooks):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
make check # lint + test + security-audit
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This runs:
|
|
24
|
+
- `agent-harness lint` — 10 checks (ruff, ty, conftest, yamllint, etc.)
|
|
25
|
+
- `uv run pytest tests/ -v` — 201 Python tests
|
|
26
|
+
- `conftest verify` — 109 Rego policy tests
|
|
27
|
+
- `agent-harness security-audit` — dependency + secret scanning
|
|
28
|
+
|
|
29
|
+
## Adding a new Rego policy
|
|
30
|
+
|
|
31
|
+
One file per concern, one concern per file.
|
|
32
|
+
|
|
33
|
+
### 1. Decide: is it deterministic?
|
|
34
|
+
|
|
35
|
+
The harness only contains deterministic controls — tools that produce a pass/fail verdict without human judgment. If a rule requires interpretation, it's guidance (document it in the skill), not a policy.
|
|
36
|
+
|
|
37
|
+
### 2. Choose the right directory
|
|
38
|
+
|
|
39
|
+
- `src/agent_harness/policies/dockerfile/` — Dockerfile rules
|
|
40
|
+
- `src/agent_harness/policies/compose/` — Docker Compose rules
|
|
41
|
+
- `src/agent_harness/policies/dokploy/` — Dokploy/Traefik rules
|
|
42
|
+
- `src/agent_harness/policies/python/` — pyproject.toml / Python config rules
|
|
43
|
+
- `src/agent_harness/policies/gitignore/` — .gitignore rules
|
|
44
|
+
|
|
45
|
+
### 3. Write the .rego file
|
|
46
|
+
|
|
47
|
+
```rego
|
|
48
|
+
package dockerfile.my_concern
|
|
49
|
+
|
|
50
|
+
# One-line description.
|
|
51
|
+
# Why this matters for AI agents.
|
|
52
|
+
#
|
|
53
|
+
# Input: <describe the parsed data structure>
|
|
54
|
+
|
|
55
|
+
import rego.v1
|
|
56
|
+
|
|
57
|
+
default _exceptions := []
|
|
58
|
+
|
|
59
|
+
_exceptions := data.exceptions if {
|
|
60
|
+
data.exceptions
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
deny contains msg if {
|
|
64
|
+
not "dockerfile.my_concern" in _exceptions
|
|
65
|
+
# your logic here
|
|
66
|
+
msg := "Actionable error message — what's wrong and how to fix it"
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Conventions:**
|
|
71
|
+
- One file per concern (e.g., `layers.rego`, `cache.rego`)
|
|
72
|
+
- Package name matches directory + filename: `policies/dockerfile/layers.rego` → `package dockerfile.layers`
|
|
73
|
+
- Only `deny` rules. No `warn`.
|
|
74
|
+
- Error messages must be actionable — tell the agent what to do
|
|
75
|
+
- WHAT/WHY/WITHOUT IT/FIX comment block at top
|
|
76
|
+
- Always include `_exceptions` guard so policies can be skipped via `conftest_skip`
|
|
77
|
+
|
|
78
|
+
### 4. Write the test file
|
|
79
|
+
|
|
80
|
+
Every policy needs a `_test.rego` sibling with at least:
|
|
81
|
+
|
|
82
|
+
```rego
|
|
83
|
+
package dockerfile.my_concern_test
|
|
84
|
+
|
|
85
|
+
import rego.v1
|
|
86
|
+
import data.dockerfile.my_concern
|
|
87
|
+
|
|
88
|
+
test_bad_input_fires if {
|
|
89
|
+
my_concern.deny with input as [...]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
test_good_input_passes if {
|
|
93
|
+
count(my_concern.deny) == 0 with input as [...]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
test_exception_skips if {
|
|
97
|
+
count(my_concern.deny) == 0 with input as [...]
|
|
98
|
+
with data.exceptions as ["dockerfile.my_concern"]
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 5. Write fixture files
|
|
103
|
+
|
|
104
|
+
Place in `tests/fixtures/<directory>/`:
|
|
105
|
+
- `bad_*.Dockerfile` — triggers the deny
|
|
106
|
+
- `good_*.Dockerfile` — passes clean
|
|
107
|
+
|
|
108
|
+
Bad fixtures should ONLY fail on the rule being tested. Include USER, HEALTHCHECK, cache mount, etc. so they don't trigger unrelated rules.
|
|
109
|
+
|
|
110
|
+
### 6. Verify
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Rego unit tests
|
|
114
|
+
conftest verify --policy src/agent_harness/policies/dockerfile/
|
|
115
|
+
|
|
116
|
+
# Fixture tests
|
|
117
|
+
conftest test tests/fixtures/dockerfile/*.Dockerfile \
|
|
118
|
+
--parser dockerfile \
|
|
119
|
+
-p src/agent_harness/policies/dockerfile/ \
|
|
120
|
+
--all-namespaces
|
|
121
|
+
|
|
122
|
+
# Full quality gate
|
|
123
|
+
make check
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 7. Update exception ID table
|
|
127
|
+
|
|
128
|
+
Add the new exception ID to `skills/agent-harness/SKILL.md` in the Conftest Exceptions table.
|
|
129
|
+
|
|
130
|
+
## Adding a new preset
|
|
131
|
+
|
|
132
|
+
1. Create `presets/<name>/` with `__init__.py` implementing `Preset`
|
|
133
|
+
2. Add individual check files (one per tool, with WHAT/WHY/WITHOUT IT/FIX docstring)
|
|
134
|
+
3. Add `<Name>Preset()` to `registry.py`
|
|
135
|
+
4. Add Rego policies to `policies/<name>/` if needed
|
|
136
|
+
5. Run `make check`
|
|
137
|
+
|
|
138
|
+
## Adding a new check module
|
|
139
|
+
|
|
140
|
+
Create a new file in `src/agent_harness/presets/<stack>/`. Follow the existing pattern:
|
|
141
|
+
|
|
142
|
+
- Function takes `project_dir: Path` and returns `CheckResult` (or `list[CheckResult]`)
|
|
143
|
+
- Use `run_check()` from `agent_harness.runner` for subprocess execution
|
|
144
|
+
- Wire the call into the preset's `run_checks()` method
|
|
145
|
+
|
|
146
|
+
## Evaluating community rules
|
|
147
|
+
|
|
148
|
+
Before writing a custom Rego rule, check if an existing tool covers it:
|
|
149
|
+
|
|
150
|
+
1. **Does hadolint cover it?** (Dockerfile shell practices) → Don't duplicate
|
|
151
|
+
2. **Does ruff cover it?** (Python code patterns) → Don't duplicate
|
|
152
|
+
3. **Does yamllint cover it?** (YAML syntax) → Don't duplicate
|
|
153
|
+
4. **Does a conftest community policy exist?** → Evaluate for adoption
|
|
154
|
+
5. **Does Trivy's built-in check cover it?** → Note the DS-* ID, write our own (Trivy is too slow)
|
|
155
|
+
|
|
156
|
+
If an existing tool covers it, don't duplicate in Rego.
|
|
157
|
+
|
|
158
|
+
### When NOT to write a rule
|
|
159
|
+
|
|
160
|
+
- **It requires file existence checks** — conftest parses content, not filesystem
|
|
161
|
+
- **It requires cross-file analysis** — conftest checks one file at a time
|
|
162
|
+
- **It's a judgment call** — document as guidance in the skill, not as a Rego policy
|
|
163
|
+
- **An existing tool does it better** — hadolint, ruff, yamllint have years of battle-tested rules
|
|
164
|
+
|
|
165
|
+
## Tool stack
|
|
166
|
+
|
|
167
|
+
| Tool | Purpose | Why this one |
|
|
168
|
+
|------|---------|-------------|
|
|
169
|
+
| conftest | Rego policies for any config file | Only tool that parses TOML + Dockerfile + YAML + JSON + .gitignore |
|
|
170
|
+
| hadolint | Dockerfile shell best practices | 12K stars, maintained, comprehensive |
|
|
171
|
+
| yamllint | YAML syntax + duplicate key detection | Catches duplicate keys conftest's parser silently merges |
|
|
172
|
+
| ruff | Python lint + format | 46K stars, fastest Python linter |
|
|
173
|
+
| ty | Python type checking | Astral's type checker, fast |
|
|
174
|
+
|
|
175
|
+
## Code style
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
make fix # auto-format + lint
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Follow existing patterns. Ruff handles formatting automatically.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Denis Iorlas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.PHONY: lint fix test check security-audit bootstrap
|
|
2
|
+
|
|
3
|
+
lint:
|
|
4
|
+
agent-harness lint
|
|
5
|
+
|
|
6
|
+
fix:
|
|
7
|
+
agent-harness fix
|
|
8
|
+
|
|
9
|
+
test:
|
|
10
|
+
uv run pytest tests/ -v
|
|
11
|
+
conftest verify -p src/agent_harness/policies/ --no-color
|
|
12
|
+
|
|
13
|
+
security-audit:
|
|
14
|
+
agent-harness security-audit
|
|
15
|
+
|
|
16
|
+
check: lint test security-audit
|
|
17
|
+
|
|
18
|
+
bootstrap: ## First-time setup after clone
|
|
19
|
+
uv sync
|
|
20
|
+
agent-harness init --apply
|
|
21
|
+
@if command -v prek >/dev/null; then prek install; \
|
|
22
|
+
elif command -v pre-commit >/dev/null; then pre-commit install; \
|
|
23
|
+
else echo "Install prek (brew install prek) or pre-commit for git hooks"; fi
|
|
24
|
+
@echo "Done. Run 'make check' to verify."
|