@terpjs/spec 0.14.0
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.
- package/LICENSE +201 -0
- package/README.md +417 -0
- package/VERSION +1 -0
- package/app-check-report.schema.json +122 -0
- package/assurance-profile.schema.json +70 -0
- package/catalog/backend/alembic_downgrades_not_empty.json +22 -0
- package/catalog/backend/base_query_not_overridden.json +27 -0
- package/catalog/backend/canonical_module_shape.json +22 -0
- package/catalog/backend/datetime_columns_are_timezone_aware.json +23 -0
- package/catalog/backend/escape_hatch_budget.json +21 -0
- package/catalog/backend/events_reference_catalog.json +27 -0
- package/catalog/backend/input_schemas_exclude_managed_columns.json +27 -0
- package/catalog/backend/input_str_fields_have_max_length.json +22 -0
- package/catalog/backend/jobs_reference_catalog.json +27 -0
- package/catalog/backend/list_routes_paginate.json +32 -0
- package/catalog/backend/modules_declare_policy.json +26 -0
- package/catalog/backend/mutations_emit_audit.json +26 -0
- package/catalog/backend/mutations_require_write_role.json +32 -0
- package/catalog/backend/no_adhoc_background_runtime.json +22 -0
- package/catalog/backend/no_adhoc_config_decrypt.json +27 -0
- package/catalog/backend/no_adhoc_logging_config.json +22 -0
- package/catalog/backend/no_adhoc_middleware.json +27 -0
- package/catalog/backend/no_adhoc_permission_literals.json +27 -0
- package/catalog/backend/no_app_instantiation.json +22 -0
- package/catalog/backend/no_blocking_sleep.json +22 -0
- package/catalog/backend/no_cross_module_imports.json +21 -0
- package/catalog/backend/no_dependency_overrides.json +27 -0
- package/catalog/backend/no_destructive_migrations.json +22 -0
- package/catalog/backend/no_dynamic_sql.json +22 -0
- package/catalog/backend/no_empty_tests.json +22 -0
- package/catalog/backend/no_eval_or_exec.json +22 -0
- package/catalog/backend/no_hardcoded_credentials.json +21 -0
- package/catalog/backend/no_internal_imports.json +22 -0
- package/catalog/backend/no_manual_actor_stamping.json +27 -0
- package/catalog/backend/no_manual_ownership_checks.json +32 -0
- package/catalog/backend/no_manual_scope_filtering.json +27 -0
- package/catalog/backend/no_manual_table_schema.json +22 -0
- package/catalog/backend/no_manual_version_assignment.json +22 -0
- package/catalog/backend/no_mutable_default_args.json +22 -0
- package/catalog/backend/no_naive_datetime.json +22 -0
- package/catalog/backend/no_oversized_python_files.json +22 -0
- package/catalog/backend/no_print.json +22 -0
- package/catalog/backend/no_raw_app_routes.json +26 -0
- package/catalog/backend/no_raw_connection_access.json +27 -0
- package/catalog/backend/no_raw_file_references.json +27 -0
- package/catalog/backend/no_raw_outbound_http.json +22 -0
- package/catalog/backend/no_raw_session_construction.json +22 -0
- package/catalog/backend/no_star_imports.json +22 -0
- package/catalog/backend/no_todo_fixme.json +22 -0
- package/catalog/backend/no_unique_columns_on_soft_delete_models.json +22 -0
- package/catalog/backend/offset_queries_declare_ordering.json +22 -0
- package/catalog/backend/path_id_params_are_uuid.json +22 -0
- package/catalog/backend/policy_refs_resolve.json +27 -0
- package/catalog/backend/public_modules_are_read_only.json +26 -0
- package/catalog/backend/reads_use_base_query.json +27 -0
- package/catalog/backend/response_model_not_table_model.json +27 -0
- package/catalog/backend/routes_declare_response_model.json +27 -0
- package/catalog/backend/safe_methods_are_read_only.json +31 -0
- package/catalog/backend/schemas_exclude_sensitive_fields.json +32 -0
- package/catalog/backend/session_imported_from_sqlmodel.json +22 -0
- package/catalog/backend/table_models_use_base_table.json +22 -0
- package/catalog/backend/tables_have_migrations.json +27 -0
- package/catalog/backend/tenant_scoped_models_use_scoped_service.json +22 -0
- package/catalog/backend/ungoverned_escape_hatch.json +21 -0
- package/catalog/backend/update_schemas_inherit_base_update_schema.json +32 -0
- package/catalog/frontend/escape-hatch.json +21 -0
- package/catalog/frontend/generated-client-only.json +26 -0
- package/catalog/frontend/layout-contract.json +26 -0
- package/catalog/frontend/no-cross-module-imports.json +21 -0
- package/catalog/frontend/no-deep-imports.json +25 -0
- package/catalog/frontend/no-dom-html-injection.json +22 -0
- package/catalog/frontend/no-eval.json +21 -0
- package/catalog/frontend/no-inline-styling.json +25 -0
- package/catalog/frontend/no-style-imports.json +24 -0
- package/catalog/frontend/no-unsafe-href.json +21 -0
- package/catalog/frontend/no-unsafe-target-blank.json +21 -0
- package/catalog/frontend/router-links.json +22 -0
- package/catalog/frontend/token-styled-elements.json +25 -0
- package/catalog/schema.json +95 -0
- package/corpus/PENDING.json +4 -0
- package/corpus/RESIDUALS.json +21 -0
- package/corpus/backend/alembic_downgrades_not_empty/compliant-01/modules/notes/migrations/versions/0001_change.py +6 -0
- package/corpus/backend/alembic_downgrades_not_empty/violation-01/modules/notes/migrations/versions/0001_change.py +6 -0
- package/corpus/backend/base_query_not_overridden/compliant-01/modules/notes/service.py +8 -0
- package/corpus/backend/base_query_not_overridden/compliant-02/modules/notes/service.py +8 -0
- package/corpus/backend/base_query_not_overridden/violation-01/modules/notes/service.py +8 -0
- package/corpus/backend/base_query_not_overridden/violation-02/expected-findings.json +7 -0
- package/corpus/backend/base_query_not_overridden/violation-02/modules/notes/service.py +8 -0
- package/corpus/backend/canonical_module_shape/compliant-01/modules/notes/models.py +6 -0
- package/corpus/backend/canonical_module_shape/compliant-01/modules/notes/module.py +7 -0
- package/corpus/backend/canonical_module_shape/compliant-01/modules/notes/router.py +3 -0
- package/corpus/backend/canonical_module_shape/compliant-01/modules/notes/schemas.py +10 -0
- package/corpus/backend/canonical_module_shape/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/canonical_module_shape/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/datetime_columns_are_timezone_aware/compliant-01/modules/notes/models.py +12 -0
- package/corpus/backend/datetime_columns_are_timezone_aware/violation-01/modules/notes/models.py +12 -0
- package/corpus/backend/datetime_columns_are_timezone_aware/violation-02/modules/notes/models.py +13 -0
- package/corpus/backend/datetime_columns_are_timezone_aware/violation-03/modules/notes/models.py +15 -0
- package/corpus/backend/escape_hatch_budget/compliant-01/escape-hatch-budget.json +3 -0
- package/corpus/backend/escape_hatch_budget/compliant-01/modules/notes/service.py +2 -0
- package/corpus/backend/escape_hatch_budget/compliant-02/escape-hatch-budget.json +1 -0
- package/corpus/backend/escape_hatch_budget/compliant-02/modules/notes/service.py +4 -0
- package/corpus/backend/escape_hatch_budget/violation-01/escape-hatch-budget.json +1 -0
- package/corpus/backend/escape_hatch_budget/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/escape_hatch_budget/violation-02/escape-hatch-budget.json +3 -0
- package/corpus/backend/escape_hatch_budget/violation-02/modules/notes/service.py +4 -0
- package/corpus/backend/events_reference_catalog/compliant-01/modules/notes/module.py +9 -0
- package/corpus/backend/events_reference_catalog/violation-01/modules/notes/module.py +8 -0
- package/corpus/backend/input_schemas_exclude_managed_columns/compliant-01/modules/notes/schemas.py +6 -0
- package/corpus/backend/input_schemas_exclude_managed_columns/violation-01/expected-findings.json +7 -0
- package/corpus/backend/input_schemas_exclude_managed_columns/violation-01/modules/notes/schemas.py +9 -0
- package/corpus/backend/input_schemas_exclude_managed_columns/violation-02/expected-findings.json +12 -0
- package/corpus/backend/input_schemas_exclude_managed_columns/violation-02/modules/notes/router.py +14 -0
- package/corpus/backend/input_str_fields_have_max_length/compliant-01/modules/notes/schemas.py +4 -0
- package/corpus/backend/input_str_fields_have_max_length/violation-01/modules/notes/schemas.py +2 -0
- package/corpus/backend/jobs_reference_catalog/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/jobs_reference_catalog/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/list_routes_paginate/compliant-01/modules/notes/router.py +6 -0
- package/corpus/backend/list_routes_paginate/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/modules_declare_policy/compliant-01/modules/notes/module.py +7 -0
- package/corpus/backend/modules_declare_policy/violation-01/modules/notes/module.py +6 -0
- package/corpus/backend/mutations_emit_audit/compliant-01/modules/notes/service.py +9 -0
- package/corpus/backend/mutations_emit_audit/violation-01/modules/notes/service.py +4 -0
- package/corpus/backend/mutations_require_write_role/compliant-01/modules/notes/module.py +7 -0
- package/corpus/backend/mutations_require_write_role/compliant-01/modules/notes/router.py +3 -0
- package/corpus/backend/mutations_require_write_role/compliant-02/modules/notes/module.py +7 -0
- package/corpus/backend/mutations_require_write_role/compliant-02/modules/notes/router.py +3 -0
- package/corpus/backend/mutations_require_write_role/violation-01/expected-findings.json +7 -0
- package/corpus/backend/mutations_require_write_role/violation-01/modules/notes/module.py +7 -0
- package/corpus/backend/mutations_require_write_role/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/mutations_require_write_role/violation-02/expected-findings.json +7 -0
- package/corpus/backend/mutations_require_write_role/violation-02/modules/notes/module.py +7 -0
- package/corpus/backend/mutations_require_write_role/violation-02/modules/notes/router.py +5 -0
- package/corpus/backend/mutations_require_write_role/violation-03/expected-findings.json +7 -0
- package/corpus/backend/mutations_require_write_role/violation-03/modules/notes/module.py +10 -0
- package/corpus/backend/mutations_require_write_role/violation-03/modules/notes/router.py +3 -0
- package/corpus/backend/no_adhoc_background_runtime/compliant-01/modules/notes/service.py +9 -0
- package/corpus/backend/no_adhoc_background_runtime/violation-01/modules/notes/service.py +5 -0
- package/corpus/backend/no_adhoc_background_runtime/violation-02/modules/notes/service.py +3 -0
- package/corpus/backend/no_adhoc_config_decrypt/compliant-01/modules/billing/service.py +2 -0
- package/corpus/backend/no_adhoc_config_decrypt/violation-01/modules/billing/service.py +2 -0
- package/corpus/backend/no_adhoc_logging_config/compliant-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_adhoc_logging_config/violation-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_adhoc_middleware/compliant-01/main.py +3 -0
- package/corpus/backend/no_adhoc_middleware/violation-01/main.py +4 -0
- package/corpus/backend/no_adhoc_middleware/violation-02/main.py +5 -0
- package/corpus/backend/no_adhoc_permission_literals/compliant-01/modules/notes/module.py +3 -0
- package/corpus/backend/no_adhoc_permission_literals/compliant-02/modules/notes/router.py +5 -0
- package/corpus/backend/no_adhoc_permission_literals/violation-01/expected-findings.json +7 -0
- package/corpus/backend/no_adhoc_permission_literals/violation-01/modules/notes/module.py +1 -0
- package/corpus/backend/no_adhoc_permission_literals/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_adhoc_permission_literals/violation-02/modules/notes/router.py +2 -0
- package/corpus/backend/no_adhoc_permission_literals/violation-03/expected-findings.json +12 -0
- package/corpus/backend/no_adhoc_permission_literals/violation-03/modules/notes/module.py +10 -0
- package/corpus/backend/no_app_instantiation/compliant-01/main.py +3 -0
- package/corpus/backend/no_app_instantiation/violation-01/main.py +3 -0
- package/corpus/backend/no_blocking_sleep/compliant-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_blocking_sleep/violation-01/modules/notes/service.py +5 -0
- package/corpus/backend/no_cross_module_imports/compliant-01/modules/a/service.py +1 -0
- package/corpus/backend/no_cross_module_imports/violation-01/modules/a/service.py +1 -0
- package/corpus/backend/no_cross_module_imports/violation-02/modules/a/service.py +1 -0
- package/corpus/backend/no_dependency_overrides/compliant-01/main.py +12 -0
- package/corpus/backend/no_dependency_overrides/violation-01/main.py +11 -0
- package/corpus/backend/no_destructive_migrations/compliant-01/modules/notes/migrations/versions/0001_change.py +3 -0
- package/corpus/backend/no_destructive_migrations/compliant-02/modules/notes/migrations/versions/0001_change.py +8 -0
- package/corpus/backend/no_destructive_migrations/violation-01/expected-findings.json +7 -0
- package/corpus/backend/no_destructive_migrations/violation-01/modules/notes/migrations/versions/0001_change.py +2 -0
- package/corpus/backend/no_destructive_migrations/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_destructive_migrations/violation-02/modules/notes/migrations/versions/0001_change.py +2 -0
- package/corpus/backend/no_destructive_migrations/violation-03/expected-findings.json +7 -0
- package/corpus/backend/no_destructive_migrations/violation-03/modules/notes/migrations/versions/0001_change.py +3 -0
- package/corpus/backend/no_destructive_migrations/violation-04/expected-findings.json +12 -0
- package/corpus/backend/no_destructive_migrations/violation-04/modules/notes/migrations/versions/0001_change.py +6 -0
- package/corpus/backend/no_destructive_migrations/violation-05/expected-findings.json +12 -0
- package/corpus/backend/no_destructive_migrations/violation-05/modules/notes/migrations/versions/0001_change.py +3 -0
- package/corpus/backend/no_dynamic_sql/compliant-01/modules/notes/service.py +1 -0
- package/corpus/backend/no_dynamic_sql/compliant-02/modules/notes/service.py +20 -0
- package/corpus/backend/no_dynamic_sql/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_dynamic_sql/violation-02/modules/notes/service.py +2 -0
- package/corpus/backend/no_dynamic_sql/violation-03/modules/notes/service.py +7 -0
- package/corpus/backend/no_dynamic_sql/violation-04/modules/notes/service.py +16 -0
- package/corpus/backend/no_empty_tests/compliant-01/tests/test_notes.py +2 -0
- package/corpus/backend/no_empty_tests/violation-01/tests/test_notes.py +2 -0
- package/corpus/backend/no_eval_or_exec/compliant-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_eval_or_exec/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_hardcoded_credentials/compliant-01/modules/billing/service.py +3 -0
- package/corpus/backend/no_hardcoded_credentials/compliant-02/modules/billing/service.py +18 -0
- package/corpus/backend/no_hardcoded_credentials/violation-01/expected-findings.json +7 -0
- package/corpus/backend/no_hardcoded_credentials/violation-01/modules/billing/service.py +2 -0
- package/corpus/backend/no_hardcoded_credentials/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_hardcoded_credentials/violation-02/modules/billing/service.py +1 -0
- package/corpus/backend/no_hardcoded_credentials/violation-03/expected-findings.json +22 -0
- package/corpus/backend/no_hardcoded_credentials/violation-03/modules/billing/service.py +11 -0
- package/corpus/backend/no_hardcoded_credentials/violation-04/expected-findings.json +12 -0
- package/corpus/backend/no_hardcoded_credentials/violation-04/modules/billing/service.py +8 -0
- package/corpus/backend/no_hardcoded_credentials/violation-05/expected-findings.json +12 -0
- package/corpus/backend/no_hardcoded_credentials/violation-05/modules/billing/service.py +4 -0
- package/corpus/backend/no_internal_imports/compliant-01/modules/notes/service.py +1 -0
- package/corpus/backend/no_internal_imports/violation-01/modules/notes/service.py +1 -0
- package/corpus/backend/no_manual_actor_stamping/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/no_manual_actor_stamping/compliant-02/modules/notes/schemas.py +12 -0
- package/corpus/backend/no_manual_actor_stamping/violation-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_manual_actor_stamping/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_manual_actor_stamping/violation-02/modules/notes/service.py +4 -0
- package/corpus/backend/no_manual_ownership_checks/compliant-01/modules/journals/service.py +3 -0
- package/corpus/backend/no_manual_ownership_checks/compliant-02/modules/journals/schemas.py +11 -0
- package/corpus/backend/no_manual_ownership_checks/violation-01/modules/journals/service.py +3 -0
- package/corpus/backend/no_manual_ownership_checks/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_manual_ownership_checks/violation-02/modules/journals/service.py +9 -0
- package/corpus/backend/no_manual_ownership_checks/violation-03/expected-findings.json +7 -0
- package/corpus/backend/no_manual_ownership_checks/violation-03/modules/notes/jobs.py +1 -0
- package/corpus/backend/no_manual_ownership_checks/violation-03/modules/notes/models.py +7 -0
- package/corpus/backend/no_manual_ownership_checks/violation-03/modules/notes/module.py +11 -0
- package/corpus/backend/no_manual_ownership_checks/violation-03/modules/notes/service.py +7 -0
- package/corpus/backend/no_manual_scope_filtering/compliant-01/modules/notes/service.py +8 -0
- package/corpus/backend/no_manual_scope_filtering/compliant-02/modules/notes/schemas.py +12 -0
- package/corpus/backend/no_manual_scope_filtering/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_manual_scope_filtering/violation-02/modules/notes/service.py +2 -0
- package/corpus/backend/no_manual_scope_filtering/violation-03/expected-findings.json +7 -0
- package/corpus/backend/no_manual_scope_filtering/violation-03/modules/notes/service.py +7 -0
- package/corpus/backend/no_manual_table_schema/compliant-01/modules/notes/models.py +6 -0
- package/corpus/backend/no_manual_table_schema/violation-01/modules/notes/models.py +8 -0
- package/corpus/backend/no_manual_version_assignment/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/no_manual_version_assignment/violation-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_manual_version_assignment/violation-02/modules/notes/service.py +3 -0
- package/corpus/backend/no_manual_version_assignment/violation-03/modules/notes/service.py +3 -0
- package/corpus/backend/no_mutable_default_args/compliant-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_mutable_default_args/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_naive_datetime/compliant-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_naive_datetime/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_naive_datetime/violation-02/modules/notes/service.py +2 -0
- package/corpus/backend/no_oversized_python_files/compliant-01/modules/notes/service.py +9 -0
- package/corpus/backend/no_oversized_python_files/violation-01/modules/notes/service.py +530 -0
- package/corpus/backend/no_print/compliant-01/modules/notes/service.py +7 -0
- package/corpus/backend/no_print/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_raw_app_routes/compliant-01/main.py +12 -0
- package/corpus/backend/no_raw_app_routes/violation-01/main.py +10 -0
- package/corpus/backend/no_raw_app_routes/violation-02/main.py +16 -0
- package/corpus/backend/no_raw_app_routes/violation-03/main.py +12 -0
- package/corpus/backend/no_raw_app_routes/violation-04/main.py +10 -0
- package/corpus/backend/no_raw_app_routes/violation-05/main.py +12 -0
- package/corpus/backend/no_raw_app_routes/violation-06/main.py +10 -0
- package/corpus/backend/no_raw_connection_access/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/no_raw_connection_access/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_raw_connection_access/violation-02/modules/notes/service.py +2 -0
- package/corpus/backend/no_raw_file_references/compliant-01/modules/notes/models.py +10 -0
- package/corpus/backend/no_raw_file_references/violation-01/modules/notes/models.py +9 -0
- package/corpus/backend/no_raw_outbound_http/compliant-01/modules/notes/service.py +2 -0
- package/corpus/backend/no_raw_outbound_http/compliant-03/modules/notes/service.py +12 -0
- package/corpus/backend/no_raw_outbound_http/violation-01/expected-findings.json +7 -0
- package/corpus/backend/no_raw_outbound_http/violation-01/modules/notes/service.py +1 -0
- package/corpus/backend/no_raw_outbound_http/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_raw_outbound_http/violation-02/modules/notes/service.py +1 -0
- package/corpus/backend/no_raw_outbound_http/violation-03/expected-findings.json +7 -0
- package/corpus/backend/no_raw_outbound_http/violation-03/modules/notes/service.py +1 -0
- package/corpus/backend/no_raw_outbound_http/violation-04/expected-findings.json +12 -0
- package/corpus/backend/no_raw_outbound_http/violation-04/modules/notes/service.py +7 -0
- package/corpus/backend/no_raw_outbound_http/violation-05/expected-findings.json +12 -0
- package/corpus/backend/no_raw_outbound_http/violation-05/modules/notes/service.py +5 -0
- package/corpus/backend/no_raw_outbound_http/violation-06/expected-findings.json +12 -0
- package/corpus/backend/no_raw_outbound_http/violation-06/modules/notes/service.py +2 -0
- package/corpus/backend/no_raw_session_construction/compliant-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_raw_session_construction/violation-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_star_imports/compliant-01/modules/notes/service.py +1 -0
- package/corpus/backend/no_star_imports/violation-01/modules/notes/service.py +1 -0
- package/corpus/backend/no_todo_fixme/compliant-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_todo_fixme/violation-01/modules/notes/service.py +3 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/compliant-01/modules/notes/models.py +17 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/violation-01/expected-findings.json +7 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/violation-01/modules/notes/models.py +6 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/violation-02/expected-findings.json +7 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/violation-02/modules/notes/models.py +13 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/violation-03/expected-findings.json +7 -0
- package/corpus/backend/no_unique_columns_on_soft_delete_models/violation-03/modules/notes/models.py +16 -0
- package/corpus/backend/offset_queries_declare_ordering/compliant-01/modules/notes/service.py +4 -0
- package/corpus/backend/offset_queries_declare_ordering/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/path_id_params_are_uuid/compliant-01/modules/notes/router.py +6 -0
- package/corpus/backend/path_id_params_are_uuid/violation-01/modules/notes/router.py +6 -0
- package/corpus/backend/policy_refs_resolve/compliant-01/modules/notes/module.py +7 -0
- package/corpus/backend/policy_refs_resolve/violation-01/modules/notes/module.py +8 -0
- package/corpus/backend/public_modules_are_read_only/compliant-01/modules/notes/module.py +7 -0
- package/corpus/backend/public_modules_are_read_only/compliant-01/modules/notes/router.py +3 -0
- package/corpus/backend/public_modules_are_read_only/violation-01/expected-findings.json +7 -0
- package/corpus/backend/public_modules_are_read_only/violation-01/modules/notes/module.py +7 -0
- package/corpus/backend/public_modules_are_read_only/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/public_modules_are_read_only/violation-02/expected-findings.json +7 -0
- package/corpus/backend/public_modules_are_read_only/violation-02/modules/notes/module.py +7 -0
- package/corpus/backend/public_modules_are_read_only/violation-02/modules/notes/router.py +5 -0
- package/corpus/backend/reads_use_base_query/compliant-01/modules/notes/models.py +6 -0
- package/corpus/backend/reads_use_base_query/compliant-01/modules/notes/service.py +8 -0
- package/corpus/backend/reads_use_base_query/compliant-02/modules/notes/models.py +9 -0
- package/corpus/backend/reads_use_base_query/compliant-02/modules/notes/service.py +9 -0
- package/corpus/backend/reads_use_base_query/violation-01/modules/notes/models.py +6 -0
- package/corpus/backend/reads_use_base_query/violation-01/modules/notes/service.py +9 -0
- package/corpus/backend/reads_use_base_query/violation-02/expected-findings.json +7 -0
- package/corpus/backend/reads_use_base_query/violation-02/modules/notes/models.py +6 -0
- package/corpus/backend/reads_use_base_query/violation-02/modules/notes/service.py +8 -0
- package/corpus/backend/response_model_not_table_model/compliant-01/modules/notes/models.py +6 -0
- package/corpus/backend/response_model_not_table_model/compliant-01/modules/notes/router.py +3 -0
- package/corpus/backend/response_model_not_table_model/compliant-01/modules/notes/schemas.py +5 -0
- package/corpus/backend/response_model_not_table_model/violation-01/modules/notes/models.py +6 -0
- package/corpus/backend/response_model_not_table_model/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/routes_declare_response_model/compliant-01/modules/notes/router.py +8 -0
- package/corpus/backend/routes_declare_response_model/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/safe_methods_are_read_only/compliant-01/modules/notes/router.py +6 -0
- package/corpus/backend/safe_methods_are_read_only/compliant-02/modules/notes/router.py +5 -0
- package/corpus/backend/safe_methods_are_read_only/violation-01/expected-findings.json +7 -0
- package/corpus/backend/safe_methods_are_read_only/violation-01/modules/notes/router.py +3 -0
- package/corpus/backend/safe_methods_are_read_only/violation-02/expected-findings.json +7 -0
- package/corpus/backend/safe_methods_are_read_only/violation-02/modules/notes/router.py +5 -0
- package/corpus/backend/safe_methods_are_read_only/violation-03/expected-findings.json +7 -0
- package/corpus/backend/safe_methods_are_read_only/violation-03/modules/notes/router.py +3 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/compliant-01/modules/users/schemas.py +5 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/compliant-02/modules/accounts/schemas.py +12 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/violation-01/expected-findings.json +7 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/violation-01/modules/users/schemas.py +3 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/violation-02/expected-findings.json +7 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/violation-02/modules/connectors/router.py +8 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/violation-03/expected-findings.json +17 -0
- package/corpus/backend/schemas_exclude_sensitive_fields/violation-03/modules/integrations/schemas.py +7 -0
- package/corpus/backend/session_imported_from_sqlmodel/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/session_imported_from_sqlmodel/violation-01/modules/notes/service.py +5 -0
- package/corpus/backend/table_models_use_base_table/compliant-01/modules/notes/models.py +6 -0
- package/corpus/backend/table_models_use_base_table/violation-01/modules/notes/models.py +5 -0
- package/corpus/backend/tables_have_migrations/compliant-01/modules/notes/migrations/versions/0a1b2c3d4e5f_create_notes_tables.py +22 -0
- package/corpus/backend/tables_have_migrations/compliant-01/modules/notes/models.py +6 -0
- package/corpus/backend/tables_have_migrations/compliant-02/capabilities/ledger/models.py +6 -0
- package/corpus/backend/tables_have_migrations/violation-01/expected-findings.json +7 -0
- package/corpus/backend/tables_have_migrations/violation-01/modules/notes/models.py +6 -0
- package/corpus/backend/tables_have_migrations/violation-02/expected-findings.json +7 -0
- package/corpus/backend/tables_have_migrations/violation-02/modules/notes/models.py +10 -0
- package/corpus/backend/tenant_scoped_models_use_scoped_service/compliant-01/modules/projects/models.py +6 -0
- package/corpus/backend/tenant_scoped_models_use_scoped_service/compliant-01/modules/projects/service.py +5 -0
- package/corpus/backend/tenant_scoped_models_use_scoped_service/compliant-02/modules/projects/models.py +8 -0
- package/corpus/backend/tenant_scoped_models_use_scoped_service/compliant-02/modules/projects/service.py +5 -0
- package/corpus/backend/tenant_scoped_models_use_scoped_service/violation-01/modules/projects/models.py +6 -0
- package/corpus/backend/tenant_scoped_models_use_scoped_service/violation-01/modules/projects/service.py +5 -0
- package/corpus/backend/ungoverned_escape_hatch/compliant-01/modules/notes/service.py +5 -0
- package/corpus/backend/ungoverned_escape_hatch/compliant-02/modules/notes/service.py +4 -0
- package/corpus/backend/ungoverned_escape_hatch/violation-01/modules/notes/service.py +2 -0
- package/corpus/backend/update_schemas_inherit_base_update_schema/compliant-01/modules/notes/schemas.py +2 -0
- package/corpus/backend/update_schemas_inherit_base_update_schema/violation-01/modules/notes/schemas.py +2 -0
- package/corpus/backend/update_schemas_inherit_base_update_schema/violation-02/modules/notes/schemas.py +5 -0
- package/corpus/frontend/escape-hatch/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/escape-hatch/violation-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/escape-hatch/violation-02/src/modules/widgets/Widget.tsx +7 -0
- package/corpus/frontend/escape-hatch/violation-03/src/modules/widgets/Widget.tsx +7 -0
- package/corpus/frontend/generated-client-only/compliant-01/src/modules/widgets/Widget.tsx +6 -0
- package/corpus/frontend/generated-client-only/compliant-02/src/modules/widgets/Widget.tsx +21 -0
- package/corpus/frontend/generated-client-only/compliant-03/src/modules/widgets/Widget.tsx +7 -0
- package/corpus/frontend/generated-client-only/compliant-04/src/modules/widgets/Widget.tsx +17 -0
- package/corpus/frontend/generated-client-only/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/generated-client-only/violation-02/src/modules/widgets/Widget.tsx +9 -0
- package/corpus/frontend/generated-client-only/violation-03/src/modules/widgets/Widget.tsx +14 -0
- package/corpus/frontend/generated-client-only/violation-04/src/modules/widgets/Widget.tsx +6 -0
- package/corpus/frontend/layout-contract/compliant-01/layout-contract.json +3 -0
- package/corpus/frontend/layout-contract/compliant-01/src/modules/widgets/Widget.tsx +8 -0
- package/corpus/frontend/layout-contract/violation-01/layout-contract.json +3 -0
- package/corpus/frontend/layout-contract/violation-01/src/modules/widgets/Widget.tsx +8 -0
- package/corpus/frontend/no-cross-module-imports/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/no-cross-module-imports/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-deep-imports/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/no-deep-imports/violation-01/src/modules/widgets/Widget.tsx +2 -0
- package/corpus/frontend/no-dom-html-injection/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/no-dom-html-injection/compliant-02/src/modules/widgets/Widget.tsx +11 -0
- package/corpus/frontend/no-dom-html-injection/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-dom-html-injection/violation-02/src/modules/widgets/Widget.tsx +7 -0
- package/corpus/frontend/no-dom-html-injection/violation-03/src/modules/widgets/Widget.tsx +12 -0
- package/corpus/frontend/no-eval/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/no-eval/compliant-02/src/modules/widgets/Widget.tsx +11 -0
- package/corpus/frontend/no-eval/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-eval/violation-02/src/modules/widgets/Widget.tsx +7 -0
- package/corpus/frontend/no-eval/violation-03/src/modules/widgets/Widget.tsx +10 -0
- package/corpus/frontend/no-eval/violation-04/src/modules/widgets/Widget.tsx +6 -0
- package/corpus/frontend/no-inline-styling/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/no-inline-styling/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-inline-styling/violation-02/src/modules/widgets/Widget.tsx +6 -0
- package/corpus/frontend/no-style-imports/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/no-style-imports/violation-01/src/modules/widgets/Widget.tsx +2 -0
- package/corpus/frontend/no-unsafe-href/compliant-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-unsafe-href/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-unsafe-target-blank/compliant-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/no-unsafe-target-blank/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/router-links/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/router-links/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/corpus/frontend/token-styled-elements/compliant-01/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/token-styled-elements/compliant-02/src/modules/widgets/Widget.tsx +4 -0
- package/corpus/frontend/token-styled-elements/violation-01/src/modules/widgets/Widget.tsx +3 -0
- package/findings.schema.json +40 -0
- package/package.json +23 -0
- package/restricted-surface.json +10 -0
- package/scorecard.schema.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# The Terp Standard — rule catalog + violation corpus
|
|
2
|
+
|
|
3
|
+
This repository is the **stack-neutral specification** of Terp's
|
|
4
|
+
secure-by-default rules (ADR 0080, made consumable by ADR 0081). The framework
|
|
5
|
+
([terp-framework](https://github.com/AITT-NL/terp-framework)) is the
|
|
6
|
+
**reference implementation**; this spec is what any other stack would
|
|
7
|
+
implement and be verified against. It is deliberately self-contained (no
|
|
8
|
+
`terp.*` imports, plain JSON + sample files) and consumed as a **package**,
|
|
9
|
+
never a repo path (ADR 0082).
|
|
10
|
+
|
|
11
|
+
## The package seam (ADR 0082)
|
|
12
|
+
|
|
13
|
+
The directory doubles as two thin distributions over one data set:
|
|
14
|
+
|
|
15
|
+
- **`terp-spec`** (Python, `pyproject.toml`): a dependency-free `terp_spec`
|
|
16
|
+
accessor — `spec_dir()` returns the on-disk spec root, `spec_version()` the
|
|
17
|
+
`VERSION` semver. A uv workspace member; the framework's certification tests
|
|
18
|
+
locate the spec only through it.
|
|
19
|
+
- **`@terpjs/spec`** (npm, `package.json`): data only; consumers resolve the
|
|
20
|
+
spec root via `require.resolve("@terpjs/spec/package.json")`. An npm workspace
|
|
21
|
+
member; the ESLint adapter's corpus/surface tests depend on it.
|
|
22
|
+
|
|
23
|
+
Both are **published from the tag workflow** (ADR 0086) — `terp-spec` on PyPI,
|
|
24
|
+
`@terpjs/spec` on npm, via Trusted Publishing (OIDC), so a consumer pins an
|
|
25
|
+
ordinary version. Pinning the git tag instead keeps working.
|
|
26
|
+
|
|
27
|
+
Both manifests carry the **spec version** (`VERSION`) — independent of the
|
|
28
|
+
platform's lockstep release version, per ADR 0081's certification model; the
|
|
29
|
+
standalone suite holds the three declarations equal.
|
|
30
|
+
|
|
31
|
+
The spec-only validations (versioning, schema validity, the refused surface's
|
|
32
|
+
shape, the corpus ratchet and directory discipline) live in `spec/tests/` and
|
|
33
|
+
run standalone (`python -m pytest` from `spec/`; CI: the path-filtered
|
|
34
|
+
`spec.yml` workflow). The framework gate keeps the *parity* half — everything
|
|
35
|
+
that needs the live implementations. Because the framework consumes a **pinned
|
|
36
|
+
release**, this repository's CI additionally runs `certify-against-reference`:
|
|
37
|
+
it checks out the reference framework, substitutes the candidate spec for the
|
|
38
|
+
pinned `terp-spec` / `@terpjs/spec`, and runs the framework's parity + corpus
|
|
39
|
+
certification — so a catalog or corpus change is proven against the live
|
|
40
|
+
implementations *before* release, and the framework's later pin bump re-proves
|
|
41
|
+
it in the framework's own gate. Splitting the spec out is then purely a
|
|
42
|
+
manifest change: move `spec/` + `spec.yml`, repin `terp-spec` / `@terpjs/spec`
|
|
43
|
+
from workspace sources to a git tag or registry release
|
|
44
|
+
(`tests/architecture/test_repo_split_readiness.py` fails the build if code
|
|
45
|
+
re-couples the units by path).
|
|
46
|
+
|
|
47
|
+
The artifacts:
|
|
48
|
+
|
|
49
|
+
1. **`VERSION`** — the semver of the standard. A checker certified against the
|
|
50
|
+
corpus records the spec version it was certified for.
|
|
51
|
+
2. **The catalog** (`catalog/`) — one JSON document per rule (validated by
|
|
52
|
+
`catalog/schema.json`): what the rule is, why it exists, and how it is
|
|
53
|
+
enforced today.
|
|
54
|
+
3. **The corpus** (`corpus/`) — violating and compliant code samples per rule:
|
|
55
|
+
the executable meaning of the rule. `corpus/PENDING.json` is the coverage
|
|
56
|
+
ratchet — the explicit list of rules still without cases, which only shrinks.
|
|
57
|
+
4. **The finding format** (`findings.schema.json`) — what a conformant checker
|
|
58
|
+
emits, so checkers are interoperable and a corpus harness can be generic.
|
|
59
|
+
5. **The check-report format** (`app-check-report.schema.json`) — the complete
|
|
60
|
+
result of one checker invocation over one application tree: the finding
|
|
61
|
+
format plus the run's own evaluated-rule inventory, spec version, checker
|
|
62
|
+
identity and verdict, so a driving tool can join per-rule verdicts to the
|
|
63
|
+
catalog fail-closed.
|
|
64
|
+
6. **The refused surface** (`restricted-surface.json`) — the stack-neutral,
|
|
65
|
+
normative declaration of the raw frontend primitives an app module must not
|
|
66
|
+
author (elements, attributes, egress globals/member calls, stylesheet
|
|
67
|
+
extensions, deep-import segments). The portable prohibition rules cite it
|
|
68
|
+
structurally (the `restricted_surface` catalog field); which sanctioned
|
|
69
|
+
component answers each primitive is per-stack configuration.
|
|
70
|
+
7. **The residual ratchet** (`corpus/RESIDUALS.json`) — the statically-erased
|
|
71
|
+
or renamed forms deliberately outside the corpus contract, per rule, as
|
|
72
|
+
shrink-only data (see "Detector boundaries" below).
|
|
73
|
+
8. **The scorecard format** (`scorecard.schema.json`) — the machine-readable
|
|
74
|
+
certification summary a conformant checker emits (spec version, per-rule
|
|
75
|
+
verdicts over the corpus, residuals claimed), so "certified against spec
|
|
76
|
+
X.Y.Z" is a verifiable artifact instead of a claim.
|
|
77
|
+
9. **The changelog** (`CHANGELOG.md`) — the change history keyed to `VERSION`
|
|
78
|
+
(the top entry must match, held by the spec suite), so a checker certified
|
|
79
|
+
against an earlier version can see exactly what changed since.
|
|
80
|
+
10. **The rule pages** (`docs/rules/`) — plain-language documentation generated
|
|
81
|
+
from the catalog (`tools/generate_rule_docs.py`; regenerate-and-compare
|
|
82
|
+
parity in the spec suite, so the pages cannot drift from the data).
|
|
83
|
+
|
|
84
|
+
Everything is locked to the live implementations by build-time parity tests
|
|
85
|
+
(`tests/architecture/test_spec_catalog.py`, `tests/architecture/test_spec_corpus.py`,
|
|
86
|
+
`packages/frontend/eslint-boundaries/src/corpus.test.js` and
|
|
87
|
+
`packages/frontend/eslint-boundaries/src/surface.test.js` — the latter holds the
|
|
88
|
+
reference adapter to `restricted-surface.json` both structurally and
|
|
89
|
+
behaviourally), following the
|
|
90
|
+
same "docs can't lie" discipline as the rest of the gate: a rule cannot ship
|
|
91
|
+
without a catalog entry, a catalog entry cannot outlive its rule, and every
|
|
92
|
+
enforcement reference must resolve to real code.
|
|
93
|
+
|
|
94
|
+
## Scope: what the standard claims — and delegates
|
|
95
|
+
|
|
96
|
+
The catalog is **Terp-specific secure architecture, not complete application
|
|
97
|
+
security**. A rule is admitted only when Terp provides a *privileged seam* or
|
|
98
|
+
a *more precise invariant* than a generic analyzer can state — a framework
|
|
99
|
+
chokepoint to pair with (`runtime.applicability: required`), a
|
|
100
|
+
refused-surface entry, a trait/registry the rule holds code to. Generic
|
|
101
|
+
vulnerability classes that stock security analyzers already detect well
|
|
102
|
+
(command injection, unsafe deserialization, weak security randomness, …) are
|
|
103
|
+
**delegated, never duplicated**: a conformant toolchain
|
|
104
|
+
runs a generic security baseline for its language *next to* the Terp rules
|
|
105
|
+
(the reference stack pins ruff's bandit-derived `S` rules, wired into the
|
|
106
|
+
platform repo, the client template, and each generated project's own gate —
|
|
107
|
+
platform ADR 0085). Classes no stock analyzer detects well — path traversal,
|
|
108
|
+
secrets in logs, browser-storage auth material — are addressed
|
|
109
|
+
**constructively** by the reference framework (streamed storage behind
|
|
110
|
+
declared references, central log redaction, the session/refresh model) and
|
|
111
|
+
earn a detective catalog rule only through the same admission bar, never as a
|
|
112
|
+
checkbox. Baseline findings are **not** Terp findings: the finding
|
|
113
|
+
format's `rule` pattern admits only catalog ids, so a generic finding can
|
|
114
|
+
never masquerade as (or dilute) a Terp verdict — it travels as the baseline
|
|
115
|
+
tool's own output (or the envelope's `unattributed` bucket, ADR 0083).
|
|
116
|
+
|
|
117
|
+
Catalog entries deliberately carry **no CWE/OWASP mappings**: no governance
|
|
118
|
+
consumer exists for them, and the delegated baseline's own documentation
|
|
119
|
+
already maps the generic classes. Metadata joins the catalog when something
|
|
120
|
+
machine-consumes it, not before.
|
|
121
|
+
|
|
122
|
+
## Catalog format
|
|
123
|
+
|
|
124
|
+
`catalog/<surface>/<rule>.json`, validated against `catalog/schema.json` (the
|
|
125
|
+
schema is normative and travels with the spec). The normative statement of a
|
|
126
|
+
rule is its `title` + `intent`, and that prose is **stack-neutral by
|
|
127
|
+
construction**: plain prose, no docstring markup, no reference-implementation
|
|
128
|
+
symbols, package paths, marker spellings, or repo-internal pointers (sibling
|
|
129
|
+
rules are cited by catalog rule name). The reference realisation lives in the
|
|
130
|
+
non-normative fields (`enforcement`, `reference`, `opt_out`, `guide_topic`).
|
|
131
|
+
The standalone suite enforces the split
|
|
132
|
+
(`test_normative_prose_is_stack_neutral`).
|
|
133
|
+
|
|
134
|
+
| Field | Meaning |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `id` | `<surface>/<rule>` — `backend/<snake_case>` (a `terp.arch` rule) or `frontend/<kebab-case>` (a boundary rule). **Findings are attributed to this id**, never to a tool-internal rule id. |
|
|
137
|
+
| `surface` | `backend` or `frontend`. |
|
|
138
|
+
| `title` | One-line statement of the invariant. |
|
|
139
|
+
| `intent` | Why the rule exists — the drift or threat it prevents. |
|
|
140
|
+
| `layer` | Cheapest faithful verification for a *new* stack: see below. |
|
|
141
|
+
| `enforcement` | How the reference implementation enforces it (first entry: the `build-time` check). A `runtime` entry names the fail-closed runtime control pairing with it (the two-layer discipline a Level 3 stack must reproduce for the rules that require it); a `black-box` entry names the `@terp/conformance` probe title. For frontend rules, `reported_as` is the ESLint rule id violations surface as — several catalog rules share one core rule id, so the adapter publishes a `catalogRuleId()` mapping and findings are attributed through it. |
|
|
142
|
+
| `runtime` | **Mandatory.** The rule's runtime-applicability classification (`required` / `not-applicable` / `deferred`) plus a `rationale` (mandatory for exemptions) and, for `deferred`, a `tracking` reference naming where the deferral is tracked — see “Runtime applicability” below. |
|
|
143
|
+
| `restricted_surface` | Frontend prohibition rules only: the `restricted-surface.json` keys the rule realises — the structural citation the spec suite resolves (every key must be claimed by some rule; a prose mention in `intent` must agree with the field). |
|
|
144
|
+
| `opt_out` | The *reference realisation* of the abstract escape-hatch contract (see below). |
|
|
145
|
+
| `reference` | Optional reference-implementation metadata: the compliant realisation the reference stack offers (component / helper names). **Not normative** — the `title` and `intent` state the stack-neutral invariant; another stack ships its own realisation. |
|
|
146
|
+
| `guide_topic` | Reference-implementation metadata (backend only): the `terp guide` topic teaching the compliant pattern. Not normative for other stacks. |
|
|
147
|
+
| `corpus` | Whether `corpus/<id>/` cases exist yet (the parity test holds this flag to the directory truth; a covered rule needs at least one `violation-*` **and** one `compliant-*` case). |
|
|
148
|
+
|
|
149
|
+
### Enforcement layers
|
|
150
|
+
|
|
151
|
+
- **`black-box`** — the invariant is observable by probing a *running* app
|
|
152
|
+
(no source access needed). Portable to any stack via a conformance suite;
|
|
153
|
+
each such rule names its probe in a `black-box` enforcement entry
|
|
154
|
+
(`packages/frontend/conformance/tests/standard.spec.ts`).
|
|
155
|
+
- **`static-portable`** — expressible as source patterns a generic engine
|
|
156
|
+
(Semgrep/ast-grep-class) can realise per language from this spec.
|
|
157
|
+
- **`static-bespoke`** — needs deep framework knowledge (traits, `ModuleSpec`,
|
|
158
|
+
archetype slots); built per officially certified stack only.
|
|
159
|
+
|
|
160
|
+
The classification is a judgment about *porting cost*, not a limit on the
|
|
161
|
+
reference implementation — today every rule is enforced by `terp.arch` or
|
|
162
|
+
`@terp/eslint-boundaries` regardless of layer.
|
|
163
|
+
|
|
164
|
+
### Runtime applicability (the two-layer discipline, per rule)
|
|
165
|
+
|
|
166
|
+
Whether a rule *additionally* pairs with a fail-closed runtime control is not a
|
|
167
|
+
blanket claim — it is recorded per rule in the mandatory `runtime` block and
|
|
168
|
+
held coherent by the spec suite:
|
|
169
|
+
|
|
170
|
+
- **`required`** — the invariant is observable in the running system and the
|
|
171
|
+
reference implementation owns a fail-closed control for it; the entry **must**
|
|
172
|
+
declare that control as a `kind: "runtime"` enforcement entry (whose `ref`
|
|
173
|
+
must resolve to a real symbol — the framework's parity test fails otherwise).
|
|
174
|
+
- **`not-applicable`** — the invariant is a property of the authored artifact
|
|
175
|
+
(source form, imports, justification markers, checked-in files) that is
|
|
176
|
+
erased or already materialised by the time the app runs, so no runtime seam
|
|
177
|
+
can enforce it. The mandatory `rationale` states why; the build-time check is
|
|
178
|
+
the control, by recorded decision.
|
|
179
|
+
- **`deferred`** — a runtime control would add independent fidelity on a seam
|
|
180
|
+
the reference framework owns, but has not shipped yet: an explicit, reviewed
|
|
181
|
+
gap, never a silent one. The mandatory `rationale` names the seam, and the
|
|
182
|
+
mandatory `tracking` reference names where the deferral is tracked (an issue
|
|
183
|
+
URL or the reference implementation's tracker document plus the seam) — so a
|
|
184
|
+
deferral has a lifecycle instead of being open-ended.
|
|
185
|
+
|
|
186
|
+
Fail-closed consistency (spec suite): `required` iff a `runtime` enforcement
|
|
187
|
+
entry exists; an exemption always carries a non-empty rationale; a deferral
|
|
188
|
+
always carries a tracking reference.
|
|
189
|
+
|
|
190
|
+
### The escape-hatch contract
|
|
191
|
+
|
|
192
|
+
Every rule has **at most one** governed opt-out, and its *semantics* are the
|
|
193
|
+
normative part: a **justified inline marker** on (or immediately above) the
|
|
194
|
+
violating line that names the **catalog rule name** (the `<rule>` half of the
|
|
195
|
+
id — never a tool-internal rule id, mirroring findings attribution) and states
|
|
196
|
+
a reason; an unjustified marker is itself a violation; marker counts must
|
|
197
|
+
exactly match a checked-in per-app budget that can only shrink (the ratchet).
|
|
198
|
+
The `opt_out` field records the reference realisation's concrete spelling
|
|
199
|
+
(`# arch-allow-<rule>: <reason>` in Python, `// terp-allow-<rule>: <reason>`
|
|
200
|
+
in TypeScript) — the spelling is derived from the rule id, and the spec suite
|
|
201
|
+
holds the derivation. The escape-hatch **governance rules themselves** (the
|
|
202
|
+
budget ratchet, the ungoverned-marker condition) carry no `opt_out`:
|
|
203
|
+
governance cannot be waived by the mechanism it governs. Another stack
|
|
204
|
+
implements the same contract with its own comment syntax.
|
|
205
|
+
|
|
206
|
+
The `<reason>` is free text, and MAY carry structured metadata tokens so a
|
|
207
|
+
long-lived exception stays visible and auditable rather than eternal:
|
|
208
|
+
`owner:<who>` (who answers for the exception), `ticket:<ref>` (where its
|
|
209
|
+
removal is tracked), and `review-by:<YYYY-MM-DD>` (when it must be re-justified).
|
|
210
|
+
The tokens are a convention, not a gate — the marker's semantics are unchanged,
|
|
211
|
+
and a checker MUST NOT reject a reason without them — but a toolchain SHOULD
|
|
212
|
+
surface expired `review-by:` dates in its reporting.
|
|
213
|
+
|
|
214
|
+
## Finding format
|
|
215
|
+
|
|
216
|
+
A conformant checker emits an array of findings per checked tree, shaped by
|
|
217
|
+
`findings.schema.json`: each finding names the **catalog rule id** it realises
|
|
218
|
+
(`rule`), the file `path` relative to the checked tree's root, and optionally a
|
|
219
|
+
`line`, a directive `message`, a `fix_hint` (the compliant construct, for agent
|
|
220
|
+
consumers acting on findings without re-reading the catalog), and a
|
|
221
|
+
`fingerprint` (a stable, checker-chosen per-instance identifier so a finding
|
|
222
|
+
can be tracked across line-shifting edits). Attribution is always to the
|
|
223
|
+
stack-neutral catalog id — the reference ESLint adapter, whose core rule ids
|
|
224
|
+
are shared between several catalog rules, publishes this mapping as
|
|
225
|
+
`catalogRuleId()` in `@terp/eslint-boundaries`.
|
|
226
|
+
|
|
227
|
+
## Check-report format
|
|
228
|
+
|
|
229
|
+
Findings alone cannot support a per-rule verdict: a rule with zero findings is
|
|
230
|
+
only *passing* if the run actually evaluated it, and the consumer must never
|
|
231
|
+
supply that knowledge itself — its own catalog copy can be newer or older than
|
|
232
|
+
the checked app's pinned toolchain (version skew), and some enforcement is
|
|
233
|
+
conditional (an escape-hatch budget only when one is checked in, a layout
|
|
234
|
+
contract only when the app opts in). So a conformant checker reports a whole
|
|
235
|
+
run as one **application check report** (`app-check-report.schema.json`): a
|
|
236
|
+
format marker (`terp_check_report: 1`), the **spec version** its rule ids
|
|
237
|
+
resolve against, the **checker identity** (the same identity its certification
|
|
238
|
+
scorecard carries), the run **verdict** (`ok`, or an explicit `error` for a
|
|
239
|
+
run that failed to complete — an erroring run never claims ok and never claims
|
|
240
|
+
rules it did not finish evaluating), the **evaluated-rule inventory**
|
|
241
|
+
(`rules`), the opt-in rules published as **`not_applicable`** (their own
|
|
242
|
+
state — never passing, never unknown), the **findings** (exactly the finding
|
|
243
|
+
format's item shape — the spec suite holds the two identical), and
|
|
244
|
+
**`unattributed`** messages (diagnostics outside the standard, surfaced rather
|
|
245
|
+
than dropped). A consumer joins per-rule verdicts to the catalog exclusively
|
|
246
|
+
through the report's inventory, fail closed: pass = evaluated with no
|
|
247
|
+
attributed finding; a rule the run did not publish renders unknown, never
|
|
248
|
+
green. A multi-surface toolchain emits one report per checker run and a
|
|
249
|
+
consumer merges reports through their inventories.
|
|
250
|
+
|
|
251
|
+
## Scorecard format
|
|
252
|
+
|
|
253
|
+
A checker claiming certification emits a scorecard (`scorecard.schema.json`):
|
|
254
|
+
the spec version it certified against, the checker's identity, and one entry
|
|
255
|
+
per claimed rule with its pass/fail verdict over the corpus and the residuals
|
|
256
|
+
it relies on (which must be a subset of `corpus/RESIDUALS.json` for the rule —
|
|
257
|
+
claiming an unrecorded residual is a conformance failure). A consumer can
|
|
258
|
+
re-run the corpus and reproduce the scorecard, making the certification claim
|
|
259
|
+
verifiable.
|
|
260
|
+
|
|
261
|
+
## Assurance profile
|
|
262
|
+
|
|
263
|
+
Conformance to the rule catalog proves the *Terp-specific* half of release
|
|
264
|
+
readiness. The **assurance profile** (`assurance-profile.schema.json`) is the
|
|
265
|
+
machine-readable composition of that with the generic evidence lanes a release
|
|
266
|
+
also stands on — one document a toolchain emits from its release verification
|
|
267
|
+
profile, so "this build is releasable" becomes a checkable artifact instead of
|
|
268
|
+
a habit.
|
|
269
|
+
|
|
270
|
+
The lane vocabulary and each lane's requirement level are **normative** and
|
|
271
|
+
fixed here — an emitter cannot demote a required lane, which is why the
|
|
272
|
+
requirement level is deliberately not a field of the document:
|
|
273
|
+
|
|
274
|
+
| Lane | Requirement | Evidence |
|
|
275
|
+
|---|---|---|
|
|
276
|
+
| `terp-standard` | **required** | The standard's own enforcement surfaces ran and passed: the architecture gate and the frontend boundary lint, publishing their evaluated-rule inventories (check reports). |
|
|
277
|
+
| `appsec-baseline` | **required** | The delegated generic AppSec baseline passed (the reference realisation: `ruff` with the flake8-bandit `S` rules). |
|
|
278
|
+
| `dependency-audit` | **required** | Dependency trees were audited against known-vulnerability databases (the reference realisation: `pip-audit` and `npm audit`). |
|
|
279
|
+
| `a11y` | recommended | Automated accessibility checks over the running app (e.g. axe). |
|
|
280
|
+
| `blackbox-conformance` | recommended | The black-box behavioural conformance suite over the running workbench. |
|
|
281
|
+
|
|
282
|
+
The claim (`ok`) is true exactly when every **required** lane passed;
|
|
283
|
+
recommended lanes inform the reader but never carry the claim. Every lane of
|
|
284
|
+
the vocabulary appears exactly once — a lane the toolchain does not realise is
|
|
285
|
+
reported `not-run` (with no composing checks), never dropped and never counted
|
|
286
|
+
as passed. Each realised lane names the verification-check ids whose verdicts
|
|
287
|
+
compose it, so a consumer can trace the claim into the toolchain's own
|
|
288
|
+
verification envelope.
|
|
289
|
+
|
|
290
|
+
## Corpus format
|
|
291
|
+
|
|
292
|
+
```text
|
|
293
|
+
corpus/backend/<rule>/violation-01/ # files rooted at the app package root
|
|
294
|
+
corpus/backend/<rule>/compliant-01/ # e.g. modules/notes/service.py
|
|
295
|
+
corpus/frontend/<rule>/violation-01/ # files rooted at the frontend app root
|
|
296
|
+
corpus/frontend/<rule>/compliant-01/ # e.g. src/modules/widgets/Widget.tsx
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
A case may ship an extra checker input at its root when the rule takes one:
|
|
300
|
+
the `backend/escape_hatch_budget` cases carry the `escape-hatch-budget.json`
|
|
301
|
+
the ratchet is verified against, and a frontend layout-contract case activates
|
|
302
|
+
via a `layout-contract.json` at its root.
|
|
303
|
+
|
|
304
|
+
A violation case MAY additionally ship an **`expected-findings.json`** at its
|
|
305
|
+
root: the exact findings (rule + path + line, shaped by
|
|
306
|
+
`findings.schema.json`) a maximally-precise checker emits for the rule under
|
|
307
|
+
test. A harness may assert the manifest exactly — hardening the per-case
|
|
308
|
+
contract from "flags something" to "flags the right line" — while the loose
|
|
309
|
+
contract below remains the floor for cases without one (and the ceiling a
|
|
310
|
+
checker must reach to conform). The spec suite holds every checked-in manifest
|
|
311
|
+
to the finding shape and to the case it sits in.
|
|
312
|
+
|
|
313
|
+
The contract for a checker claiming conformance for a rule is stated **per
|
|
314
|
+
rule**, over the finding format above:
|
|
315
|
+
|
|
316
|
+
- every `violation-*` case produces at least one finding attributed to that
|
|
317
|
+
rule's catalog id, and
|
|
318
|
+
- every `compliant-*` case produces **no** findings for that rule.
|
|
319
|
+
|
|
320
|
+
A compliant case is minimal, not a full application — it may legitimately be
|
|
321
|
+
incomplete with respect to *other* rules, so a multi-rule checker scopes the
|
|
322
|
+
corpus run to the rule under test. (The reference frontend harness happens to
|
|
323
|
+
hold its compliant cases fully clean across all boundary rules — a stricter
|
|
324
|
+
bar than the contract requires.)
|
|
325
|
+
|
|
326
|
+
### Detector boundaries (what the corpus deliberately does not require)
|
|
327
|
+
|
|
328
|
+
The executable corpus **is** the interoperability contract: a checker is
|
|
329
|
+
conformant for a rule when it flags every `violation-*` case and stays silent
|
|
330
|
+
on every `compliant-*` case — nothing more. The violation cases include the
|
|
331
|
+
evasion shapes the rules are expected to see through (qualified/attribute
|
|
332
|
+
calls, multiline constructs, values routed through a local variable or
|
|
333
|
+
`.format()`/`%` building, aliased and parenthesized imports, computed
|
|
334
|
+
`window["fetch"]`-style member access for the egress family), and the
|
|
335
|
+
compliant cases pin the near-misses that must **not** fire (adjacent-literal
|
|
336
|
+
SQL that merely looks concatenated, credential-shaped names with dynamic
|
|
337
|
+
values, `*_mock`/`socketserver`-style name cousins, member calls like
|
|
338
|
+
`repo.fetch(...)` / `interpreter.eval(...)` on local objects, forbidden syntax
|
|
339
|
+
quoted inside comments and strings).
|
|
340
|
+
|
|
341
|
+
Some statically-erased or renamed forms are **deliberately outside** the
|
|
342
|
+
contract — known limits of precise, low-false-positive detection, kept out of
|
|
343
|
+
the corpus so a second implementation neither over-fits nor under-claims.
|
|
344
|
+
These residuals are recorded per rule in **`corpus/RESIDUALS.json`** — a
|
|
345
|
+
machine-readable ratchet governed like `corpus/PENDING.json`: the list only
|
|
346
|
+
shrinks, and closing a residual means seeding the corpus case that contracts
|
|
347
|
+
it and deleting the entry, never silently. Today it records:
|
|
348
|
+
|
|
349
|
+
- an alias-renamed symbol import (`from sqlalchemy import text as sql_text`)
|
|
350
|
+
is not required to be resolved to `text`;
|
|
351
|
+
- dynamic import (`importlib.import_module("httpx")`) is not required to be
|
|
352
|
+
seen as an import;
|
|
353
|
+
- a computed sink or global (`el["innerHTML"] = …`, `window["eval"]`) is not
|
|
354
|
+
required to be recognised for the *eval/DOM-sink* rules (the egress family
|
|
355
|
+
**does** contract the computed forms — its cases include them);
|
|
356
|
+
- `Function("…")` called without `new`, and egress through receivers other
|
|
357
|
+
than `window`/`globalThis` (`self.fetch`), are not required.
|
|
358
|
+
|
|
359
|
+
These residuals are governed the usual way: the escape-hatch contract makes
|
|
360
|
+
sanctioned exceptions visible, and the paired runtime controls (where
|
|
361
|
+
`runtime.applicability` is `required`) hold the invariant regardless of
|
|
362
|
+
spelling. Widening a detector past the contract is always allowed — the
|
|
363
|
+
corpus states the floor, not the ceiling.
|
|
364
|
+
|
|
365
|
+
The reference implementations are themselves held to this contract in CI:
|
|
366
|
+
`test_spec_corpus.py` runs each catalogued `terp.arch` rule over the backend
|
|
367
|
+
corpus, and `corpus.test.js` runs the ESLint adapter over the frontend corpus,
|
|
368
|
+
attributing findings via `catalogRuleId()`. Corpus sample files are
|
|
369
|
+
intentionally violating code — they are excluded from repo-wide lint
|
|
370
|
+
(`ruff` `extend-exclude`) and are never imported or executed.
|
|
371
|
+
|
|
372
|
+
Coverage is governed by **`corpus/PENDING.json`**: the exact list of rules
|
|
373
|
+
still without cases. Seeding a rule's corpus removes it from the list; a new
|
|
374
|
+
rule shipped without corpus must be listed there explicitly — so uncovered
|
|
375
|
+
rules stay visible and the list only shrinks. Every `static-portable` backend
|
|
376
|
+
rule must have cases (enforced by the parity test); today every backend and
|
|
377
|
+
frontend rule has cases and the pending list is empty — it exists so a *new*
|
|
378
|
+
rule can ship with its gap explicit and reviewed.
|
|
379
|
+
|
|
380
|
+
## Conformance levels
|
|
381
|
+
|
|
382
|
+
- **Level 1 — black-box:** the app passes the runnable conformance suite
|
|
383
|
+
(`@terp/conformance`) for the capabilities it claims, including the
|
|
384
|
+
`standard:` probes the `black-box` catalog entries name.
|
|
385
|
+
- **Level 2 — static rule pack:** additionally, a checker validated against
|
|
386
|
+
this corpus enforces the `static-portable` rules for the app's language(s),
|
|
387
|
+
emitting findings per `findings.schema.json`.
|
|
388
|
+
- **Level 3 — full harness:** additionally, the `static-bespoke` rules, the
|
|
389
|
+
paired `runtime` controls of every rule whose `runtime.applicability` is
|
|
390
|
+
`required`, and the governed escape-hatch budget ratchet are enforced (today:
|
|
391
|
+
the `terp.arch` + `@terp/eslint-boundaries` reference harness on top of
|
|
392
|
+
`terp.core` / `@terp/react-core`).
|
|
393
|
+
|
|
394
|
+
## Growing the spec
|
|
395
|
+
|
|
396
|
+
- **New rule** → ship the rule and its catalog entry together (the parity test
|
|
397
|
+
fails otherwise); classify its runtime applicability deliberately (`required`
|
|
398
|
+
with the declared control, or an exemption with its rationale — a deferral
|
|
399
|
+
also names its `tracking` reference); seed corpus cases when the rule is
|
|
400
|
+
portable, or list it in `corpus/PENDING.json` explicitly; regenerate the
|
|
401
|
+
rule pages (`python tools/generate_rule_docs.py`).
|
|
402
|
+
- **New corpus cases** → add `violation-*`/`compliant-*` directories, flip the
|
|
403
|
+
entry's `corpus` flag to `true`, and drop the rule from `corpus/PENDING.json`;
|
|
404
|
+
the harness picks the cases up by convention. Ship an `expected-findings.json`
|
|
405
|
+
when the violating lines are pinned. Closing a documented detector residual
|
|
406
|
+
also deletes its `corpus/RESIDUALS.json` entry.
|
|
407
|
+
- **New stack** → implement the `static-portable` rules however you like; the
|
|
408
|
+
corpus is the acceptance test, findings must attribute to catalog ids, and
|
|
409
|
+
the certification summary is a scorecard (`scorecard.schema.json`).
|
|
410
|
+
- **Format change** → bump `VERSION` and add the matching `CHANGELOG.md` entry
|
|
411
|
+
(the suite holds the top entry to the version). Pre-1.0, a **changed
|
|
412
|
+
contract** — a new mandatory catalog field (0.5.0's `runtime` block), a
|
|
413
|
+
changed finding shape —
|
|
414
|
+
bumps the **minor** (the strongest signal 0.x semver carries; a 0.x major
|
|
415
|
+
would claim a stability this spec does not yet promise); purely additive
|
|
416
|
+
fields and new rules also bump the minor; prose bumps the patch. From 1.0.0
|
|
417
|
+
a changed contract bumps the **major**.
|
package/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.14.0
|