Skip to content

Latest commit

 

History

History
185 lines (159 loc) · 16.5 KB

File metadata and controls

185 lines (159 loc) · 16.5 KB

Enforced Rules

For representative valid and invalid test fixtures demonstrating these rules, see the Fixture Index.

Rule ID What it detects
CELLFENCE_MANIFEST_INVALID Invalid manifest or baseline configuration
CELLFENCE_PATTERN_MATCHES_NOTHING Manifest-declared include, exclude, ownership, public path, or non-external artifact pattern matched no repository files
CELLFENCE_SUSPICIOUS_GLOB_PATTERN Manifest pattern contains a glob segment such as *** that is usually a ** typo and changes depth semantics
CELLFENCE_DUPLICATE_CELL_ID Duplicate cell identifiers
CELLFENCE_OWNERSHIP_OVERLAP Overlapping declared ownership paths
CELLFENCE_OWNERSHIP_COVERAGE_DISABLED Strict ownership coverage is disabled, so source outside ownedPaths can escape checks
CELLFENCE_UNOWNED_SOURCE Strict governance found source matched by governance.include that no cell owns
CELLFENCE_UNOWNED_IMPORT_TARGET A cell imports governed source that no cell owns
CELLFENCE_IMPORT_TARGET_OUTSIDE_ROOT A source import resolved to a real file outside the repository root
CELLFENCE_PUBLIC_ENTRY_OUTSIDE_OWNERSHIP A public entry or public path is outside the declaring cell's owned paths
CELLFENCE_ARTIFACT_OUTSIDE_OWNERSHIP A non-external produced artifact lane is outside the producer's owned paths
CELLFENCE_SYMLINK_TARGET_OUTSIDE_OWNERSHIP A governed symlink points outside its owning cell, outside the repository, or cannot be resolved
CELLFENCE_PRIVATE_IMPORT Cross-cell import of private implementation
CELLFENCE_UNDECLARED_CONSUMER Cross-cell dependency missing from the consumer manifest. Walkthrough
CELLFENCE_PUBLIC_ENTRY_MISSING Declared public entry does not exist
CELLFENCE_PUBLIC_SYMBOL_MISMATCH Manifest symbols do not match actual public exports
CELLFENCE_UNDECLARED_ARTIFACT Artifact lane consumption was not declared
CELLFENCE_UNDECLARED_RESOURCE_ACCESS Static file, database, queue, or HTTP resource access was not declared
CELLFENCE_UNRESOLVED_RESOURCE_ACCESS Dynamic or unsafe resource access could not be resolved safely
CELLFENCE_RESOURCE_EVIDENCE_INVALID Runtime resource evidence JSON is invalid or references an unknown cell
CELLFENCE_RESOURCE_EVIDENCE_TRANSCRIPT_INACTIVE Runtime evidence declares an inactive trace transcript, usually because the trace hook was disabled
CELLFENCE_RESOURCE_EVIDENCE_TRANSCRIPT_INCOMPLETE Runtime evidence is missing an active, trustworthy transcript or was capped/truncated before all accesses were observed
CELLFENCE_EXTERNAL_DEPENDENCY_CLAIM_VIOLATION A cell uses an external dependency claimed by another cell or claiming set
CELLFENCE_RATCHET_EXTERNAL_DEPENDENCY_ADDED A cell added a new unclaimed external dependency outside the accepted baseline
CELLFENCE_LOCKED_EXTERNAL_DEPENDENCY_EXPANSION A locked cell expanded its accepted external dependency set
CELLFENCE_PLUGIN_INVALID A programmatic plugin has an unsupported API version, throws, or emits invalid references
CELLFENCE_REQUIRED_RULE_DISABLED A configured governance.requiredRules rule was weakened
CELLFENCE_IMPORT_ANALYSIS_DISABLED Reserved compatibility rule ID; manifest v1 rejects importAnalysis: false as CELLFENCE_MANIFEST_INVALID before repository analysis
CELLFENCE_RESOURCE_ANALYSIS_DISABLED Reserved compatibility rule ID; manifest v1 rejects resourceAnalysis: false as CELLFENCE_MANIFEST_INVALID before repository analysis
CELLFENCE_CLAIM_INVALID Claim store or claim request is malformed, expired metadata is invalid, or a claim references unknown cells
CELLFENCE_ACTIVE_CLAIM_CONFLICT Two active claim leases reserve overlapping cells, paths, symbols, resources, or artifact lanes
CELLFENCE_UNCLAIMED_CHANGE claim check --agent found a changed file outside that agent's active claim
CELLFENCE_CROSS_CELL_MOVE A changed file moved between cells and needs explicit architectural review
CELLFENCE_GIT_METADATA_UNAVAILABLE CellFence could not read required Git metadata for changed-file, commit, or evidence checks
CELLFENCE_WAIVER_INVALID A waiver directive is missing a valid signed attestation, is expired, exceeds the 90-day cap, mismatches repository/source/finding bindings, uses an untrusted approver, or attempts to waive a required rule
CELLFENCE_WAIVER_UNTRUSTED_APPROVER A signed waiver attestation names an approver outside trusted CELLFENCE_APPROVERS
CELLFENCE_WAIVER_PARSING_DISABLED A cell disabled waiver directive parsing with waiverParsing: false; directives in that cell are intentionally ignored
CELLFENCE_UNRESOLVED_IMPORT Static relative import could not be resolved; fails closed
CELLFENCE_RATCHET_OWNED_PATH_GROWTH Owned path pattern count increased
CELLFENCE_RATCHET_PUBLIC_SYMBOL_GROWTH Public symbol count increased
CELLFENCE_RATCHET_PUBLIC_SURFACE_LINE_GROWTH Public entry line count increased
CELLFENCE_RATCHET_CROSS_CELL_DEPENDENCY_GROWTH Cross-cell dependency count increased
CELLFENCE_RATCHET_CELL_SET_GROWTH A cell was added outside the accepted baseline cell set
CELLFENCE_RATCHET_OWNERSHIP_SCOPE_CHANGE An owned path shifted or broadened outside the accepted baseline scope
CELLFENCE_RATCHET_PUBLIC_SYMBOL_SET_CHANGE A new public symbol appeared outside the accepted baseline set
CELLFENCE_RATCHET_DEPENDENCY_EDGE_CHANGE A new dependency edge appeared outside the accepted baseline set
CELLFENCE_RATCHET_PUBLIC_ENTRY_CHANGE A cell's public entry path changed
CELLFENCE_RATCHET_ARTIFACT_CONTRACT_CHANGE A new artifact producer/consumer contract appeared
CELLFENCE_RATCHET_RESOURCE_ACCESS_CHANGE A new static or evidence-backed resource access appeared outside the accepted baseline
CELLFENCE_RATCHET_PUBLIC_SURFACE_SIGNATURE_CHANGE Declaration-derived public surface fingerprint changed beyond formatting/comment noise
CELLFENCE_BASELINE_SEAL_INVALID A baseline seal is missing or does not match when Ed25519 or HMAC baseline verification is configured
CELLFENCE_LOCKED_BASELINE_EXPANSION A locked baseline scope expanded without an accepted ratchet update
CELLFENCE_UNSUPPORTED_DYNAMIC_REQUIRE Computed CommonJS require() cannot be resolved statically; emitted as a fail-closed required-rule finding
CELLFENCE_UNSUPPORTED_DYNAMIC_IMPORT Computed dynamic import cannot be resolved statically; emitted as a fail-closed required-rule finding
CELLFENCE_UNSUPPORTED_TYPESCRIPT_SYNTAX TypeScript or JavaScript source could not be parsed cleanly; emitted as a fail-closed required-rule finding
CELLFENCE_UNSUPPORTED_PYTHON_SYNTAX Python source could not be parsed by the configured Python AST inspector; emitted as a fail-closed required-rule finding
CELLFENCE_SOURCE_IMPORTS_RUNTIME A source-class path imports a runtime-class path in violation of path class policy
CELLFENCE_MIXED_SOURCE_RUNTIME_CHANGE A change mixes source and runtime path classes without an allowed commit policy
CELLFENCE_GENERATED_PATH_CHANGED A generated path changed without the required provenance or separation policy
CELLFENCE_SERVICE_MANIFEST_DRIFT A generated CellFence manifest drifted from declared service manifests
CELLFENCE_COMMIT_EVIDENCE_MISSING Commit-level evidence required by path class policy is missing
CELLFENCE_COMMIT_TRAILER_MISSING A required commit trailer for governed path classes is missing
CELLFENCE_COMMIT_CHANGED_CELLS_MISMATCH Commit metadata does not match the cells changed in the diff
CELLFENCE_COMMIT_TEST_EVIDENCE_MISMATCH Commit test evidence does not cover the changed cell set
CELLFENCE_COMMIT_TEST_REASON_REQUIRED Commit metadata claims weak or missing test evidence without a required reason
CELLFENCE_COMMIT_TEST_WEAKENING Commit metadata weakens required test evidence policy
CELLFENCE_TASK_INVALID A task manifest is malformed or references invalid cells, files, budgets, or allowlists
CELLFENCE_TASK_WRITE_OUTSIDE_ALLOWLIST A task attempted to write outside its declared allowed paths
CELLFENCE_TASK_FORBIDDEN_PATH A task attempted to touch a path explicitly forbidden by its manifest
CELLFENCE_TASK_CHANGE_BUDGET_EXCEEDED A task changed more cells, files, or lines than its declared budget allows
CELLFENCE_DOC_UNKNOWN_CELL A stamped architecture document references a cell that is not in the manifest
CELLFENCE_DOC_SURFACE_STALE A stamped architecture document no longer matches the current cell public surface
CELLFENCE_MUTATION_SCORE_BELOW_THRESHOLD Mutation testing score is below the configured minimum

CELLFENCE_UNDECLARED_CONSUMER walkthrough

The undeclared-consumer fixture demonstrates a public cross-cell import that lacks the required dependency declaration. Its src/consumer/public.ts imports producerValue from the producer's declared src/producer/public.ts entry. The target is public, so this is not a private-import violation.

The fixture's cellfence.manifest.json owns the files with separate consumer and producer cells, but the consumer's consumes list is empty. CellFence therefore reports CELLFENCE_UNDECLARED_CONSUMER: using a producer's public entry does not replace the manifest's explicit cross-cell dependency contract.

Build the CLI and reproduce the finding from the repository root:

npm run build
node packages/cli/dist/index.js check \
  --root fixtures/invalid/undeclared-consumer \
  --format markdown

The intentionally invalid fixture exits unsuccessfully and reports CELLFENCE_UNDECLARED_CONSUMER at src/consumer/public.ts:1. Its expected-result.json also records the expected CELLFENCE_OWNERSHIP_COVERAGE_DISABLED warning.

CellFence v0.x analyzes:

  • ES module imports;
  • export ... from declarations;
  • CommonJS require(...), TypeScript import = require(...), selected module.require(...), simple require aliases, and selected createRequire(...) aliases;
  • type-only imports;
  • dynamic imports with a static string specifier;
  • exact package-name imports declared with packageName;
  • tsconfig compilerOptions.paths aliases, including aliases inherited through extends, that resolve to repository files;
  • Python .py source ownership, AST-extracted import and from ... import ... module references, common package roots from pyproject.toml, setup.cfg, and static setup.py, and public entries described by literal __all__ or top-level declarations. Python module-level from ... import name creates a public module attribute unless hidden with an underscore alias or constrained by __all__;
  • selected static string resource access for file, database, queue, and HTTP patterns, including Node fs read/write/destructive file calls and fetch/request absolute, relative, websocket, const, and inline new URL(...) string forms;
  • Prisma model delegate calls when schema.prisma is present;
  • selected TypeORM entity, repository, and query builder calls;
  • selected Drizzle table declarations and db.select().from(...), db.insert(...), db.update(...), and db.delete(...) calls;
  • selected Kysely/Knex-style query builder table calls;
  • unsafe or dynamic raw SQL calls, known SQL receiver calls with non-literal arguments, and dynamic HTTP URL calls as fail-closed unresolved resource access;
  • selected BullMQ and KafkaJS topic or queue calls;
  • selected NestJS controller method decorators;
  • selected Fastify route object registrations;
  • runtime resource evidence supplied as cellfence.resource-evidence.v2;
  • common TypeScript export declarations, named exports, and exported namespaces;
  • common Python public symbols from __all__, top-level functions/classes/assignments, and simple re-export imports.

Computed dynamic imports, computed calls in recognized CommonJS require() forms, TypeScript/JavaScript parser diagnostics, and Python files that the configured Python AST inspector cannot parse are reported as unsupported fail-closed findings rather than silently ignored.

For TypeScript and JavaScript public entries, public surface hashes are based on isolated normalized declaration output when TypeScript can emit it, with a lightweight syntax fingerprint as a fallback. This catches type-facing changes such as generic constraints, inferred changes that appear in declarations, const literal type changes, class member signatures, and namespaces while avoiding method-body churn. It is still a v0.x contract fingerprint, not a full TypeScript semantic-versioning oracle.

NodeNext-style runtime .js, .jsx, .mjs, and .cjs relative specifiers are remapped to TypeScript source candidates such as .ts, .tsx, .mts, and .cts before boundary checks. Python imports are resolved from known source roots such as src/, manifest-derived package roots, and common Python packaging metadata. Relative imports that still cannot be resolved produce CELLFENCE_UNRESOLVED_IMPORT errors instead of being ignored. Relative, absolute, tsconfig alias, and Python source-root imports that resolve to files outside the repository root produce CELLFENCE_IMPORT_TARGET_OUTSIDE_ROOT errors instead of being treated as ungoverned or external.

The repository CI includes a synthetic scale benchmark for 10,000 files / 20 cells, 50,000 files / 100 cells, and 100,000 files / 300 cells. It is a regression tripwire for file discovery, ownership indexing, and low-signal source scanning; it is not a universal performance guarantee for every monorepo shape.

Static resource analysis is intentionally limited. It detects simple string-literal calls, SQL literals, selected Node fs calls, selected fetch/request HTTP calls, selected Prisma delegate calls, selected TypeORM, Drizzle, and query-builder calls, selected BullMQ/KafkaJS calls, selected NestJS/Fastify HTTP route declarations, selected FastAPI route decorators, Django URLConf routes and model manager calls, SQLAlchemy declarative/Table/query/text calls, and Celery task declarations and literal publish calls. When a known HTTP call has a non-static URL, or a receiver already observed as SQL later receives a non-static query argument, CellFence emits unresolved resource access instead of silently dropping the call. It does not infer arbitrary ORM metadata, runtime broker topology, framework plugin behavior, or values assembled through general dataflow.

ORMs, query builders, HTTP frameworks, and broker clients require explicit CellFence adapters. Prisma, TypeORM, Drizzle, BullMQ, KafkaJS, selected string-literal query builders, selected NestJS routes, selected Fastify routes, and selected Django, FastAPI, SQLAlchemy, and Celery Python patterns have built-in coverage; that does not imply support for Sequelize, every Knex/Kysely expression, every Drizzle expression, every NestJS/Fastify plugin, every Python framework extension, or a project-local database wrapper. Each adapter must document:

  • the API shapes it recognizes;
  • how model, entity, table, topic, or queue names are resolved;
  • which unresolved or dynamic forms fail closed;
  • which cases remain outside static inference and must be supplied as runtime evidence.

Unsupported adapters are not treated as implicitly safe. If a resource access cannot be resolved by a built-in adapter, an explicit resourceContracts entry, baseline evidence, runtime evidence, or a fail-closed unresolved finding is required depending on the access shape.

Repositories can disable unused built-in resource adapters so CellFence does not infer framework contracts for stacks the repository does not run:

{
  "governance": {
    "resourceAdapters": {
      "prisma": "off",
      "typeorm": "off",
      "drizzle": "off",
      "bullmq": "off",
      "kafkajs": "off",
      "nestjs": "off",
      "fastify": "off",
      "django": "off",
      "fastapi": "off",
      "sqlalchemy": "off",
      "celery": "off",
      "queue": "off",
      "sql-literal": "off"
    }
  }
}

Supported keys are file, http, queue, sql-literal, prisma, typeorm, drizzle, query-builder, bullmq, kafkajs, nestjs, fastify, django, fastapi, sqlalchemy, and celery. Omitted adapters default to on.