atdd 0.2.8__tar.gz → 0.3.3__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.
- {atdd-0.2.8/src/atdd.egg-info → atdd-0.3.3}/PKG-INFO +4 -2
- {atdd-0.2.8 → atdd-0.3.3}/README.md +3 -1
- {atdd-0.2.8 → atdd-0.3.3}/pyproject.toml +6 -1
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/cli.py +20 -6
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/initializer.py +10 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/inventory.py +2 -4
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/sync.py +7 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/test_runner.py +3 -3
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/templates/ATDD.md +34 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/templates/SESSION-TEMPLATE.md +34 -0
- atdd-0.3.3/src/atdd/coach/utils/__init__.py +5 -0
- atdd-0.3.3/src/atdd/coach/utils/repo.py +97 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/shared_fixtures.py +2 -0
- atdd-0.3.3/src/atdd/tester/conventions/security.convention.yaml +165 -0
- atdd-0.3.3/src/atdd/tester/validators/test_contract_security.py +569 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_contracts_structure.py +81 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/version_check.py +111 -3
- {atdd-0.2.8 → atdd-0.3.3/src/atdd.egg-info}/PKG-INFO +4 -2
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd.egg-info/SOURCES.txt +3 -0
- atdd-0.2.8/src/atdd/tester/validators/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/LICENSE +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/setup.cfg +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/__main__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/add_persistence_metadata.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/analyze_migrations.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/consumers.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/gate.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/infer_governance_status.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/interface.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/migration.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/registry.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/session.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/test_interface.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/tests/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/tests/test_telemetry_array_validation.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/commands/traceability.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/conventions/session.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/overlays/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/overlays/claude.md +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/schemas/config.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/schemas/manifest.schema.json +0 -0
- {atdd-0.2.8/src/atdd/coach/utils → atdd-0.3.3/src/atdd/coach/utils/graph}/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/utils/graph/urn.py +0 -0
- {atdd-0.2.8/src/atdd/coach/utils/graph → atdd-0.3.3/src/atdd/coach/validators}/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/test_enrich_wagon_registry.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/test_registry.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/test_session_validation.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/test_traceability.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/test_update_feature_paths.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coach/validators/test_validate_contract_consumers.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/adapter.recipe.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/backend.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/boundaries.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/commons.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/complexity.recipe.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/component-naming.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/design.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/design.recipe.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/dto.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/frontend.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/green.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/presentation.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/refactor.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/technology.convention.yaml +0 -0
- {atdd-0.2.8/src/atdd/coach/validators → atdd-0.3.3/src/atdd/coder/conventions/tests}/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/tests/test_adapter_recipe.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/tests/test_complexity_recipe.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/tests/test_component_taxonomy.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/tests/test_component_urn_naming.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/tests/test_thinness_recipe.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/thinness.recipe.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/train.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/conventions/verification.protocol.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/schemas/design_system.schema.json +0 -0
- {atdd-0.2.8/src/atdd/coder/conventions/tests → atdd-0.3.3/src/atdd/coder/validators}/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_commons_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_complexity.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_cross_language_consistency.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_design_system_compliance.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_dto_testing_patterns.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_green_cross_stack_layers.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_green_layer_dependencies.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_green_python_layer_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_green_supabase_layer_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_import_boundaries.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_init_file_urns.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_preact_layer_boundaries.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_presentation_convention.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_python_architecture.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_quality_metrics.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_station_master_pattern.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_train_infrastructure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_train_urns.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_typescript_architecture.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_usecase_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/coder/validators/test_wagon_boundaries.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/conftest.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/acceptance.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/appendix.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/artifact-naming.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/component.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/criteria.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/feature.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/interface.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/steps.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/train.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/wagon.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/conventions/wmbt.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/acceptance.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/appendix.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/component.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/feature.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/train.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/wagon.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/schemas/wmbt.schema.json +0 -0
- {atdd-0.2.8/src/atdd/coder → atdd-0.3.3/src/atdd/planner}/validators/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/conftest.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_draft_wagon_registry.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_plan_cross_refs.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_plan_uniqueness.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_plan_urn_resolution.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_plan_wagons.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_train_validation.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_wagon_urn_chain.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_wmbt_consistency.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/planner/validators/test_wmbt_vocabulary.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/artifact.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/contract.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/filename.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/migration.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/red.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/routing.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/conventions/telemetry.convention.yaml +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/a11y.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/artifact.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/contract.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/contract.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/db.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/e2e.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/edge_function.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/event.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/http.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/job.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/load.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/metric.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/pack.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/realtime.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/rls.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/script.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/sec.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/storage.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/telemetry.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/telemetry_tracking_manifest.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/test_filename.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/test_intent.schema.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/unit.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/visual.tmpl.json +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/schemas/ws.tmpl.json +0 -0
- {atdd-0.2.8/src/atdd/planner/validators → atdd-0.3.3/src/atdd/tester/utils}/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/utils/filename.py +0 -0
- {atdd-0.2.8/src/atdd/tester/utils → atdd-0.3.3/src/atdd/tester/validators}/__init__.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/cleanup_duplicate_headers.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/cleanup_duplicate_headers_v2.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/conftest.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/coverage_gap_report.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/fix_dual_ac_references.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/remove_duplicate_lines.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_acceptance_urn_filename_mapping.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_acceptance_urn_separator.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_artifact_naming_category.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_contract_schema_compliance.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_coverage_adequacy.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_dual_ac_reference.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_fixture_validity.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_isolation.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_migration_coverage.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_migration_criteria.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_migration_generation.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_python_test_naming.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_red_layer_validation.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_red_python_layer_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_red_supabase_layer_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_telemetry_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_typescript_test_naming.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd/tester/validators/test_typescript_test_structure.py +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd.egg-info/dependency_links.txt +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd.egg-info/entry_points.txt +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd.egg-info/requires.txt +0 -0
- {atdd-0.2.8 → atdd-0.3.3}/src/atdd.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atdd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: ATDD Platform - Acceptance Test Driven Development toolkit
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -54,7 +54,9 @@ atdd sync # Sync rules to agent config files
|
|
|
54
54
|
atdd --test all # Run validators
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
> **⚠️ `atdd gate` is required.**
|
|
57
|
+
> **⚠️ `atdd gate` is required.**
|
|
58
|
+
> 🤖 Tell your agent: "Run `atdd gate` and follow ATDD rigorously."
|
|
59
|
+
> Agents skip instruction files but can't ignore tool output. No gate = no ATDD guarantees.
|
|
58
60
|
|
|
59
61
|
## What It Does
|
|
60
62
|
|
|
@@ -40,7 +40,9 @@ atdd sync # Sync rules to agent config files
|
|
|
40
40
|
atdd --test all # Run validators
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
> **⚠️ `atdd gate` is required.**
|
|
43
|
+
> **⚠️ `atdd gate` is required.**
|
|
44
|
+
> 🤖 Tell your agent: "Run `atdd gate` and follow ATDD rigorously."
|
|
45
|
+
> Agents skip instruction files but can't ignore tool output. No gate = no ATDD guarantees.
|
|
44
46
|
|
|
45
47
|
## What It Does
|
|
46
48
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "atdd"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.3"
|
|
8
8
|
description = "ATDD Platform - Acceptance Test Driven Development toolkit"
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
readme = "README.md"
|
|
@@ -35,3 +35,8 @@ where = ["src"]
|
|
|
35
35
|
[tool.pytest.ini_options]
|
|
36
36
|
pythonpath = ["src"]
|
|
37
37
|
testpaths = ["src/atdd"]
|
|
38
|
+
markers = [
|
|
39
|
+
"tester: marks tests as tester validators",
|
|
40
|
+
"platform: marks tests as platform validators",
|
|
41
|
+
"security: marks tests as security validators",
|
|
42
|
+
]
|
|
@@ -44,7 +44,8 @@ from atdd.coach.commands.initializer import ProjectInitializer
|
|
|
44
44
|
from atdd.coach.commands.session import SessionManager
|
|
45
45
|
from atdd.coach.commands.sync import AgentConfigSync
|
|
46
46
|
from atdd.coach.commands.gate import ATDDGate
|
|
47
|
-
from atdd.
|
|
47
|
+
from atdd.coach.utils.repo import find_repo_root
|
|
48
|
+
from atdd.version_check import print_update_notice, print_upgrade_sync_notice
|
|
48
49
|
|
|
49
50
|
|
|
50
51
|
class ATDDCoach:
|
|
@@ -57,8 +58,8 @@ class ATDDCoach:
|
|
|
57
58
|
- Coder: Implementation phase validation
|
|
58
59
|
"""
|
|
59
60
|
|
|
60
|
-
def __init__(self):
|
|
61
|
-
self.repo_root =
|
|
61
|
+
def __init__(self, repo_root: Path = None):
|
|
62
|
+
self.repo_root = repo_root or find_repo_root()
|
|
62
63
|
self.inventory = RepositoryInventory(self.repo_root)
|
|
63
64
|
self.test_runner = TestRunner(self.repo_root)
|
|
64
65
|
self.registry_updater = RegistryUpdater(self.repo_root)
|
|
@@ -290,6 +291,14 @@ Phase descriptions:
|
|
|
290
291
|
|
|
291
292
|
# ----- Existing flag-based arguments (backwards compatible) -----
|
|
292
293
|
|
|
294
|
+
# Repository root override
|
|
295
|
+
parser.add_argument(
|
|
296
|
+
"--repo",
|
|
297
|
+
type=str,
|
|
298
|
+
metavar="PATH",
|
|
299
|
+
help="Target repository root (default: auto-detect from .atdd/)"
|
|
300
|
+
)
|
|
301
|
+
|
|
293
302
|
# Main command groups
|
|
294
303
|
parser.add_argument(
|
|
295
304
|
"--inventory",
|
|
@@ -394,8 +403,9 @@ Phase descriptions:
|
|
|
394
403
|
|
|
395
404
|
# ----- Handle flag-based commands (backwards compatible) -----
|
|
396
405
|
|
|
397
|
-
# Create coach instance
|
|
398
|
-
|
|
406
|
+
# Create coach instance with optional repo override
|
|
407
|
+
repo_path = Path(args.repo) if args.repo else None
|
|
408
|
+
coach = ATDDCoach(repo_root=repo_path)
|
|
399
409
|
|
|
400
410
|
# Handle commands
|
|
401
411
|
if args.inventory:
|
|
@@ -426,10 +436,14 @@ Phase descriptions:
|
|
|
426
436
|
|
|
427
437
|
|
|
428
438
|
def cli() -> int:
|
|
429
|
-
"""CLI entry point with version
|
|
439
|
+
"""CLI entry point with version and upgrade checks."""
|
|
440
|
+
# Check if repo needs sync after ATDD upgrade (at startup)
|
|
441
|
+
print_upgrade_sync_notice()
|
|
442
|
+
|
|
430
443
|
try:
|
|
431
444
|
result = main()
|
|
432
445
|
finally:
|
|
446
|
+
# Check for newer versions on PyPI (at end)
|
|
433
447
|
print_update_notice()
|
|
434
448
|
return result
|
|
435
449
|
|
|
@@ -160,11 +160,21 @@ class ProjectInitializer:
|
|
|
160
160
|
print(f"Config already exists: {self.config_file}")
|
|
161
161
|
return
|
|
162
162
|
|
|
163
|
+
# Get installed ATDD version
|
|
164
|
+
try:
|
|
165
|
+
from atdd import __version__
|
|
166
|
+
toolkit_version = __version__
|
|
167
|
+
except ImportError:
|
|
168
|
+
toolkit_version = "0.0.0"
|
|
169
|
+
|
|
163
170
|
config = {
|
|
164
171
|
"version": "1.0",
|
|
165
172
|
"sync": {
|
|
166
173
|
"agents": ["claude"], # Default: only Claude
|
|
167
174
|
},
|
|
175
|
+
"toolkit": {
|
|
176
|
+
"last_version": toolkit_version, # Track installed version
|
|
177
|
+
},
|
|
168
178
|
}
|
|
169
179
|
|
|
170
180
|
with open(self.config_file, "w") as f:
|
|
@@ -26,7 +26,7 @@ class RepositoryInventory:
|
|
|
26
26
|
"""Generate comprehensive repository inventory."""
|
|
27
27
|
|
|
28
28
|
def __init__(self, repo_root: Path = None):
|
|
29
|
-
self.repo_root = repo_root or Path(
|
|
29
|
+
self.repo_root = repo_root or Path.cwd()
|
|
30
30
|
self.inventory = {
|
|
31
31
|
"inventory": {
|
|
32
32
|
"generated_at": datetime.now().isoformat(),
|
|
@@ -288,7 +288,7 @@ class RepositoryInventory:
|
|
|
288
288
|
feature_files = len(python_tests) + len(ts_tests)
|
|
289
289
|
|
|
290
290
|
meta_cases = planner_cases + tester_cases + coder_cases + platform_cases
|
|
291
|
-
feature_cases = python_cases #
|
|
291
|
+
feature_cases = python_cases # TS case counting would require parsing those languages
|
|
292
292
|
|
|
293
293
|
return {
|
|
294
294
|
"total_files": meta_files + feature_files,
|
|
@@ -312,13 +312,11 @@ class RepositoryInventory:
|
|
|
312
312
|
"feature_tests": {
|
|
313
313
|
"files": {
|
|
314
314
|
"python": len(python_tests),
|
|
315
|
-
"dart": len(dart_tests),
|
|
316
315
|
"typescript": len(ts_tests),
|
|
317
316
|
"total": feature_files
|
|
318
317
|
},
|
|
319
318
|
"cases": {
|
|
320
319
|
"python": python_cases,
|
|
321
|
-
"dart": "not_counted",
|
|
322
320
|
"typescript": "not_counted",
|
|
323
321
|
"total": feature_cases
|
|
324
322
|
}
|
|
@@ -115,6 +115,13 @@ class AgentConfigSync:
|
|
|
115
115
|
unchanged_count += 1
|
|
116
116
|
|
|
117
117
|
print(f"\nSync complete: {synced_count} updated, {unchanged_count} unchanged")
|
|
118
|
+
|
|
119
|
+
# Update toolkit.last_version to mark sync complete
|
|
120
|
+
from atdd.version_check import update_toolkit_version
|
|
121
|
+
if update_toolkit_version(self.config_file):
|
|
122
|
+
from atdd import __version__
|
|
123
|
+
print(f"Updated toolkit.last_version to {__version__}")
|
|
124
|
+
|
|
118
125
|
return 0
|
|
119
126
|
|
|
120
127
|
def verify(self) -> int:
|
|
@@ -15,7 +15,7 @@ class TestRunner:
|
|
|
15
15
|
"""Run ATDD meta-tests with various configurations."""
|
|
16
16
|
|
|
17
17
|
def __init__(self, repo_root: Path = None):
|
|
18
|
-
self.repo_root = repo_root or Path(
|
|
18
|
+
self.repo_root = repo_root or Path.cwd()
|
|
19
19
|
self.atdd_dir = self.repo_root / "atdd"
|
|
20
20
|
|
|
21
21
|
def run_tests(
|
|
@@ -88,11 +88,11 @@ class TestRunner:
|
|
|
88
88
|
# Show collected tests summary
|
|
89
89
|
cmd.append("--tb=short")
|
|
90
90
|
|
|
91
|
-
# Run pytest
|
|
91
|
+
# Run pytest from current directory (consumer repo)
|
|
92
92
|
print(f"🧪 Running: {' '.join(cmd)}")
|
|
93
93
|
print("=" * 60)
|
|
94
94
|
|
|
95
|
-
result = subprocess.run(cmd
|
|
95
|
+
result = subprocess.run(cmd)
|
|
96
96
|
return result.returncode
|
|
97
97
|
|
|
98
98
|
def run_phase(self, phase: str, **kwargs) -> int:
|
|
@@ -13,6 +13,11 @@ missions:
|
|
|
13
13
|
#
|
|
14
14
|
# PROTOCOL:
|
|
15
15
|
# ---------
|
|
16
|
+
# 0. TOOL GATE (MANDATORY)
|
|
17
|
+
# If your agent supports plan mode (Claude Code, etc.), enable it NOW.
|
|
18
|
+
# This is a tool capability gate, NOT the ATDD Planner phase.
|
|
19
|
+
# If unavailable, state: "Plan mode unavailable" and proceed.
|
|
20
|
+
#
|
|
16
21
|
# 1. Run this command FIRST:
|
|
17
22
|
#
|
|
18
23
|
# atdd gate
|
|
@@ -214,6 +219,35 @@ git:
|
|
|
214
219
|
- "GREEN: commit passing implementation"
|
|
215
220
|
- "REFACTOR: commit clean architecture"
|
|
216
221
|
|
|
222
|
+
# Release Gate (MANDATORY - session completion)
|
|
223
|
+
# Every session MUST end with version bump + tag
|
|
224
|
+
release:
|
|
225
|
+
mandatory: true
|
|
226
|
+
|
|
227
|
+
rules:
|
|
228
|
+
- "Tag must match version exactly: v{version}"
|
|
229
|
+
- "No tag without version bump"
|
|
230
|
+
- "No version bump without tag"
|
|
231
|
+
- "Every repo MUST have versioning"
|
|
232
|
+
|
|
233
|
+
change_class:
|
|
234
|
+
PATCH: "bug fixes, docs, refactors, internal changes"
|
|
235
|
+
MINOR: "new feature, new validator, new command, new convention (non-breaking)"
|
|
236
|
+
MAJOR: "breaking API/CLI/schema/convention change or behavior removal"
|
|
237
|
+
|
|
238
|
+
workflow:
|
|
239
|
+
- "Determine change class"
|
|
240
|
+
- "Bump version in version file"
|
|
241
|
+
- "Commit: 'Bump version to {version}'"
|
|
242
|
+
- "Create tag: git tag v{version}"
|
|
243
|
+
- "Push with tags: git push origin {branch} --tags"
|
|
244
|
+
- "Record in Session Log: 'Released: v{version}'"
|
|
245
|
+
|
|
246
|
+
# Consumer repos configure version file location in .atdd/config.yaml:
|
|
247
|
+
# release:
|
|
248
|
+
# version_file: "pyproject.toml" # or package.json, VERSION, etc.
|
|
249
|
+
# tag_prefix: "v"
|
|
250
|
+
|
|
217
251
|
# Agent Coordination (Detailed in action files)
|
|
218
252
|
agents:
|
|
219
253
|
planner:
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# TOOL GATE (MANDATORY BEFORE FILLING THIS FILE)
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# If your agent supports plan mode (Claude Code, etc.), enable it NOW.
|
|
6
|
+
# This is a tool capability gate, NOT the ATDD Planner phase.
|
|
7
|
+
# If unavailable, state: "Plan mode unavailable" and proceed.
|
|
8
|
+
# =============================================================================
|
|
9
|
+
-->
|
|
1
10
|
---
|
|
2
11
|
# SESSION METADATA (YAML frontmatter - machine-parseable)
|
|
3
12
|
#
|
|
@@ -322,6 +331,31 @@ Reference: src/atdd/coach/conventions/session.convention.yaml
|
|
|
322
331
|
|
|
323
332
|
---
|
|
324
333
|
|
|
334
|
+
## Release Gate (MANDATORY)
|
|
335
|
+
|
|
336
|
+
<!--
|
|
337
|
+
Every session MUST end with a version bump + matching git tag.
|
|
338
|
+
|
|
339
|
+
Change Class:
|
|
340
|
+
- PATCH: bug fixes, docs, refactors, internal changes
|
|
341
|
+
- MINOR: new feature, new validator, new command, new convention (non-breaking)
|
|
342
|
+
- MAJOR: breaking API/CLI/schema/convention change or behavior removal
|
|
343
|
+
|
|
344
|
+
Rules:
|
|
345
|
+
- Tag must match version exactly: v{version}
|
|
346
|
+
- No tag without version bump
|
|
347
|
+
- No version bump without tag
|
|
348
|
+
-->
|
|
349
|
+
|
|
350
|
+
- [ ] Determine change class: PATCH / MINOR / MAJOR
|
|
351
|
+
- [ ] Bump version in version file (pyproject.toml, package.json, etc.)
|
|
352
|
+
- [ ] Commit: "Bump version to {version}"
|
|
353
|
+
- [ ] Create tag: `git tag v{version}`
|
|
354
|
+
- [ ] Push with tags: `git push origin {branch} --tags`
|
|
355
|
+
- [ ] Record tag in Session Log: "Released: v{version}"
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
325
359
|
## Notes
|
|
326
360
|
|
|
327
361
|
{Additional context, learnings, or decisions that don't fit elsewhere.}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Repository root detection utility.
|
|
3
|
+
|
|
4
|
+
Finds the consumer repository root using multiple detection strategies:
|
|
5
|
+
1. .atdd/manifest.yaml (preferred - explicit ATDD project marker)
|
|
6
|
+
2. plan/ AND contracts/ both exist (ATDD project structure)
|
|
7
|
+
3. .git/ directory (fallback - any git repo)
|
|
8
|
+
4. cwd (last resort - allows commands to work on uninitialized repos)
|
|
9
|
+
|
|
10
|
+
This ensures ATDD commands operate on the user's repo, not the package root.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from functools import lru_cache
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Optional
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@lru_cache(maxsize=1)
|
|
19
|
+
def find_repo_root(start: Optional[Path] = None) -> Path:
|
|
20
|
+
"""
|
|
21
|
+
Find repo root by searching upward for ATDD project markers.
|
|
22
|
+
|
|
23
|
+
Detection order (first match wins):
|
|
24
|
+
1. .atdd/manifest.yaml - explicit ATDD project marker
|
|
25
|
+
2. plan/ AND contracts/ both exist - ATDD project structure
|
|
26
|
+
3. .git/ directory - fallback for any git repository
|
|
27
|
+
4. cwd - last resort if no markers found
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
start: Starting directory (default: cwd)
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Path to repo root (falls back to cwd if no markers found)
|
|
34
|
+
|
|
35
|
+
Note:
|
|
36
|
+
Results are cached for performance. If .atdd/manifest.yaml is not found,
|
|
37
|
+
commands may operate in a degraded mode.
|
|
38
|
+
"""
|
|
39
|
+
current = start or Path.cwd()
|
|
40
|
+
current = current.resolve()
|
|
41
|
+
|
|
42
|
+
while current != current.parent:
|
|
43
|
+
# Strategy 1: .atdd/manifest.yaml (preferred)
|
|
44
|
+
if (current / ".atdd" / "manifest.yaml").is_file():
|
|
45
|
+
return current
|
|
46
|
+
|
|
47
|
+
# Strategy 2: plan/ AND contracts/ both exist
|
|
48
|
+
if (current / "plan").is_dir() and (current / "contracts").is_dir():
|
|
49
|
+
return current
|
|
50
|
+
|
|
51
|
+
# Strategy 3: .git/ directory (fallback)
|
|
52
|
+
if (current / ".git").is_dir():
|
|
53
|
+
return current
|
|
54
|
+
|
|
55
|
+
current = current.parent
|
|
56
|
+
|
|
57
|
+
# Strategy 4: Return starting directory as last resort
|
|
58
|
+
# Commands can handle uninitialized repos appropriately
|
|
59
|
+
return start.resolve() if start else Path.cwd().resolve()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def require_repo_root(start: Optional[Path] = None) -> Path:
|
|
63
|
+
"""
|
|
64
|
+
Find repo root, raising RuntimeError if no markers found.
|
|
65
|
+
|
|
66
|
+
This is a stricter version of find_repo_root() for commands that
|
|
67
|
+
require a valid ATDD project structure.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
start: Starting directory (default: cwd)
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Path to repo root
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
RuntimeError: If no ATDD project markers (.atdd/manifest.yaml,
|
|
77
|
+
plan/ + contracts/, or .git/) are found
|
|
78
|
+
"""
|
|
79
|
+
current = start or Path.cwd()
|
|
80
|
+
current = current.resolve()
|
|
81
|
+
start_path = current
|
|
82
|
+
|
|
83
|
+
while current != current.parent:
|
|
84
|
+
# Check for any valid marker
|
|
85
|
+
if (current / ".atdd" / "manifest.yaml").is_file():
|
|
86
|
+
return current
|
|
87
|
+
if (current / "plan").is_dir() and (current / "contracts").is_dir():
|
|
88
|
+
return current
|
|
89
|
+
if (current / ".git").is_dir():
|
|
90
|
+
return current
|
|
91
|
+
|
|
92
|
+
current = current.parent
|
|
93
|
+
|
|
94
|
+
raise RuntimeError(
|
|
95
|
+
f"No ATDD project markers found searching from {start_path}. "
|
|
96
|
+
"Expected one of: .atdd/manifest.yaml, plan/ + contracts/, or .git/"
|
|
97
|
+
)
|
|
@@ -118,6 +118,8 @@ def wagon_manifests() -> List[Tuple[Path, Dict[str, Any]]]:
|
|
|
118
118
|
manifests.append((manifest_path, manifest_data))
|
|
119
119
|
|
|
120
120
|
# Also discover individual wagon manifests (pattern: plan/*/_{wagon}.yaml)
|
|
121
|
+
if not PLAN_DIR.exists():
|
|
122
|
+
return manifests
|
|
121
123
|
for wagon_dir in PLAN_DIR.iterdir():
|
|
122
124
|
if wagon_dir.is_dir() and not wagon_dir.name.startswith("_"):
|
|
123
125
|
for manifest_file in wagon_dir.glob("_*.yaml"):
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
version: "1.0"
|
|
2
|
+
name: "Security Convention"
|
|
3
|
+
description: "Security validation rules for contract schemas"
|
|
4
|
+
|
|
5
|
+
# Validator Specifications
|
|
6
|
+
validators:
|
|
7
|
+
- id: "SPEC-TESTER-SEC-0001"
|
|
8
|
+
name: "Secured operations must declare auth headers"
|
|
9
|
+
test: "test_secured_operations_have_required_headers"
|
|
10
|
+
mode: "hard"
|
|
11
|
+
description: |
|
|
12
|
+
Secured operations must include appropriate authentication headers
|
|
13
|
+
based on their declared security scheme. This ensures that all
|
|
14
|
+
protected endpoints have proper header declarations for auth tokens.
|
|
15
|
+
|
|
16
|
+
- id: "SPEC-TESTER-SEC-0002"
|
|
17
|
+
name: "Operations must have explicit security field"
|
|
18
|
+
test: "test_operations_have_explicit_security"
|
|
19
|
+
mode: "soft (xfail)"
|
|
20
|
+
description: |
|
|
21
|
+
All API operations should declare their security requirements explicitly.
|
|
22
|
+
Use security: [] for public endpoints and security: [{...}] for protected.
|
|
23
|
+
This ensures security posture is intentional, not accidental.
|
|
24
|
+
|
|
25
|
+
- id: "SPEC-TESTER-SEC-0003"
|
|
26
|
+
name: "Secured operations need SEC/RLS acceptance coverage"
|
|
27
|
+
test: "test_secured_operations_have_security_acceptance"
|
|
28
|
+
mode: "soft (xfail)"
|
|
29
|
+
description: |
|
|
30
|
+
Secured operations must have at least one acceptance criteria using
|
|
31
|
+
the SEC (Security) or RLS (Row-Level Security) harness. This ensures
|
|
32
|
+
security requirements are tested.
|
|
33
|
+
|
|
34
|
+
- id: "SPEC-TESTER-SEC-0004"
|
|
35
|
+
name: "Error responses should not expose sensitive data"
|
|
36
|
+
test: "test_error_responses_have_no_sensitive_fields"
|
|
37
|
+
mode: "warning only"
|
|
38
|
+
description: |
|
|
39
|
+
Error responses (4xx/5xx) should not contain fields with sensitive
|
|
40
|
+
names like password, secret, credential, ssn, api_key, private_key.
|
|
41
|
+
This prevents accidental exposure of sensitive data in error messages.
|
|
42
|
+
|
|
43
|
+
# Security Scheme to Header Mapping
|
|
44
|
+
scheme_header_mapping:
|
|
45
|
+
jwt:
|
|
46
|
+
headers: ["authorization"]
|
|
47
|
+
format: "Bearer {token}"
|
|
48
|
+
description: "JSON Web Token authentication"
|
|
49
|
+
|
|
50
|
+
bearer:
|
|
51
|
+
headers: ["authorization"]
|
|
52
|
+
format: "Bearer {token}"
|
|
53
|
+
description: "Bearer token authentication"
|
|
54
|
+
|
|
55
|
+
oauth2:
|
|
56
|
+
headers: ["authorization"]
|
|
57
|
+
format: "Bearer {access_token}"
|
|
58
|
+
description: "OAuth 2.0 authentication"
|
|
59
|
+
|
|
60
|
+
http:
|
|
61
|
+
headers: ["authorization"]
|
|
62
|
+
format: "Varies by scheme (basic, bearer, digest)"
|
|
63
|
+
description: "HTTP authentication"
|
|
64
|
+
|
|
65
|
+
apiKey:
|
|
66
|
+
headers: "dynamic"
|
|
67
|
+
source: "security[].name (default: x-api-key)"
|
|
68
|
+
location: "security[].in (header, query, or cookie)"
|
|
69
|
+
description: "API Key authentication"
|
|
70
|
+
|
|
71
|
+
# Enforcement Modes
|
|
72
|
+
enforcement:
|
|
73
|
+
environment_variable: "ATDD_SECURITY_ENFORCE"
|
|
74
|
+
default: "0"
|
|
75
|
+
modes:
|
|
76
|
+
soft:
|
|
77
|
+
value: "0"
|
|
78
|
+
behavior: "pytest.xfail - test marked as expected failure"
|
|
79
|
+
visibility: "Visible in test output as XFAIL"
|
|
80
|
+
use_case: "Development, incremental adoption"
|
|
81
|
+
|
|
82
|
+
hard:
|
|
83
|
+
value: "1"
|
|
84
|
+
behavior: "pytest.fail - test fails the suite"
|
|
85
|
+
visibility: "Visible as FAILED"
|
|
86
|
+
use_case: "CI/CD, production readiness"
|
|
87
|
+
|
|
88
|
+
# Sensitive Data Detection
|
|
89
|
+
sensitive_data_detection:
|
|
90
|
+
description: "Rules for detecting potentially sensitive fields in error responses"
|
|
91
|
+
|
|
92
|
+
sensitive_fields:
|
|
93
|
+
- "password"
|
|
94
|
+
- "secret"
|
|
95
|
+
- "credential"
|
|
96
|
+
- "ssn"
|
|
97
|
+
- "api_key"
|
|
98
|
+
- "private_key"
|
|
99
|
+
- "token"
|
|
100
|
+
|
|
101
|
+
allowed_exceptions:
|
|
102
|
+
- "error_key"
|
|
103
|
+
- "key_id"
|
|
104
|
+
- "token_type"
|
|
105
|
+
|
|
106
|
+
detection_method: "Substring match (case-insensitive)"
|
|
107
|
+
note: "Review flagged fields manually - not all matches are security issues"
|
|
108
|
+
|
|
109
|
+
# Threat Modeling Integration
|
|
110
|
+
threat_modeling:
|
|
111
|
+
canonical_location: "feature.yaml: security.abuse_cases[]"
|
|
112
|
+
description: |
|
|
113
|
+
Threat models and abuse cases should be documented in the feature YAML
|
|
114
|
+
files under the security.abuse_cases array. This ensures security
|
|
115
|
+
considerations are part of the feature specification.
|
|
116
|
+
|
|
117
|
+
schema:
|
|
118
|
+
abuse_case:
|
|
119
|
+
required:
|
|
120
|
+
- id # Unique identifier (e.g., THREAT-001)
|
|
121
|
+
- name # Short name
|
|
122
|
+
- threat # Description of the threat
|
|
123
|
+
- mitigation # How the threat is addressed
|
|
124
|
+
optional:
|
|
125
|
+
- severity # low, medium, high, critical
|
|
126
|
+
- likelihood # unlikely, possible, likely
|
|
127
|
+
- acceptance_ref # URN to acceptance test covering this threat
|
|
128
|
+
|
|
129
|
+
example:
|
|
130
|
+
security:
|
|
131
|
+
abuse_cases:
|
|
132
|
+
- id: "THREAT-001"
|
|
133
|
+
name: "Session Hijacking"
|
|
134
|
+
threat: "Attacker steals session token via XSS"
|
|
135
|
+
mitigation: "HttpOnly cookies, CSP headers"
|
|
136
|
+
severity: "high"
|
|
137
|
+
acceptance_ref: "acc:auth:D001-SEC-001-session-protection"
|
|
138
|
+
|
|
139
|
+
# Acceptance Coverage Requirements
|
|
140
|
+
acceptance_coverage:
|
|
141
|
+
description: "Requirements for security acceptance test coverage"
|
|
142
|
+
|
|
143
|
+
valid_harnesses:
|
|
144
|
+
- "SEC" # Security-focused tests
|
|
145
|
+
- "RLS" # Row-Level Security tests
|
|
146
|
+
|
|
147
|
+
urn_format: "acc:{wagon}:{WMBT}-{HARNESS}-{NNN}[-{slug}]"
|
|
148
|
+
full_format_required: true
|
|
149
|
+
note: |
|
|
150
|
+
Short refs (without harness) cannot be validated for SEC/RLS coverage.
|
|
151
|
+
Always use the full URN format with the harness identifier.
|
|
152
|
+
|
|
153
|
+
examples:
|
|
154
|
+
valid:
|
|
155
|
+
- "acc:auth:D001-SEC-001-token-validation"
|
|
156
|
+
- "acc:player:P002-RLS-001-own-data-only"
|
|
157
|
+
invalid:
|
|
158
|
+
- "SEC-001" # Missing wagon and WMBT
|
|
159
|
+
- "D001-001" # Missing harness identifier
|
|
160
|
+
|
|
161
|
+
# Cross-References
|
|
162
|
+
references:
|
|
163
|
+
test_file: "atdd/tester/validators/test_contract_security.py"
|
|
164
|
+
contract_convention: "atdd/tester/conventions/contract.convention.yaml"
|
|
165
|
+
api_structure: "contract.convention.yaml#api_structure.authentication"
|