1
0
Fork 0
Code Issues Pull requests Projects Releases 2 Packages Wiki Activity Actions Pages
DocForge2/docs/SECURITY.md

127 lines
7.1 KiB
Markdown
Raw Permalink Normal View History

# Security model
DocForge is a project-bound knowledge compiler. Its security boundary is an explicit project root,
2026-07-29 16:50:39 -04:00
closed configuration, bounded data, and exact identities. It is not a general process or
filesystem sandbox.
Start with [core authority](CORE_CONCEPTS_AND_AUTHORITY.md), then use
[policy precedence](POLICY_PRECEDENCE.md) to decide which capabilities a server should expose.
## Project and path confinement
Descriptors, reference-adapter configurations, canonical sources, authority files, templates,
changesets, caches, indexes, previews, and declared outputs are resolved against one project root.
DocForge rejects absolute paths where only project-relative paths are allowed, parent traversal,
symbolic-link escapes, unsafe file types, and protected-root overlap. Important reads use
no-follow file descriptors and compare file identity before and after reading.
Confinement protects DocForge operations. It does not stop another process with repository access
from changing files. Long-running bindings revalidate descriptor and adapter implementation
identity and require a restart after drift.
2026-07-29 16:50:39 -04:00
Generic canonical application stages backups and replacements below
`.docforge/application/transaction-*` in mode-0700 directories. That private namespace confines
ordinary path access and prevents access by other users. Deliberate arbitrary tampering by another
process running as the same operating-system user is outside this boundary. DocForge still
identity-checks private files before using or removing them, but mode `0700` is not isolation from
the same UID.
## Untrusted project content
Documentation, source text, templates, adapter metadata, compiler-database entries, and changeset
content are data. They cannot redefine policy or instruct DocForge to execute a command. Generic
manual rendering disables raw HTML, accepts a fixed template vocabulary, and rejects script-like
content. Portable graph and manual workers accept validated inert packages and fixed built-in
renderer identities.
The C++ reference adapter reads `compile_commands.json` only as bounded translation-unit inventory
and fingerprint evidence. It never executes the recorded command, compiler, response file, or
project program.
## Adapter launcher boundary
`AdapterLauncherV1` contains one Python module name and project identity. It contains no command,
shell string, arbitrary argument list, working directory, environment, discovery rule, or callable
selector.
Custom modules must be installed top-level modules. An isolated `python -I` probe resolves the
module without importing it and requires its regular-file origin to remain inside the bound
project. The sole trusted dotted exception is the packaged `docforge.reference_mcp` module. Client
fragments use the exact validated interpreter and canonical fixed arguments with an empty
environment.
This proves that the declared module is resolvable and project-bound. It does not make arbitrary
module code safe. Project owners remain responsible for the implementation they install.
## Mutation boundary
Normal MCP and the fixed reference server are read-only. Proposal tools exist only when a
startup-bound writer is authorized by the descriptor. Canonical application exists only when a
matching applier is explicitly configured.
Every proposal append, rebase, abandonment, and application is hash-bound. Application requires
the exact changeset hash that was reviewed. Source identity, content hashes, permissions,
conflicts, graph validity, and serializer round trips are checked before success. DocForge never
turns prose approval into a fuzzy merge.
2026-07-29 16:50:39 -04:00
The generic applier compares exact canonical file identity immediately before each publication.
Create uses no-clobber publication. Update and delete use atomic exchange and no-replace moves.
Concurrent canonical-target mutation therefore fails closed, rolls back when the exact displaced
state is still provable, or retains recovery evidence without overwriting foreign data.
This compare-and-swap protection is not a process-death journal. One file publication is atomic,
and an in-process failure runs exact rollback, but an application spanning several canonical files
does not promise crash atomicity if the process or host dies between publications. Operators must
inspect canonical state and retained transaction evidence before retrying after such an
interruption.
## Derived state and publication
SQLite indexes, source-generation receipts, extraction caches, render fragments, previews, and
portable artifacts are disposable. Corrupt, stale, foreign, oversized, or mismatched derived
state is rejected or rebuilt from current project evidence.
2026-07-29 16:50:39 -04:00
Derived publication stages complete bounded output, flushes file and directory state, and commits
with atomic replacement or no-clobber compare-and-swap. It is crash-safe: an interruption leaves
the prior verified artifact, the complete new artifact, or explicit degraded post-commit evidence,
not a mixed publication. Generated command-reference publication also serializes cooperating
writers. A raced target is restored or retained for recovery instead of being silently discarded.
Projection and canonical-application lifecycles record when semantic content committed but later
private cleanup or receipt verification degraded. Canonical success closes the applied proposal
and persists compact `application_recovery` metadata with retained paths and remediation. A
completed mutation is never reported as an ordinary retryable failure.
## Limits and denial-of-service resistance
Inputs, results, traversal, context, changesets, renders, worker protocols, manifests, adapter
assemblies, and extraction caches have explicit count and byte limits. Incremental extraction
caches are capped at 10,000 sources and 64,000,000 bytes. Adapter primary nodes use the project
`max_nodes` limit; edges and Logic have deterministic multipliers over that limit.
Limits reduce accidental and adversarial amplification. An in-process adapter can still allocate
memory before returning data, so only trusted project-owned adapter code should run in the server
process.
## Secrets and network behavior
DocForge does not copy the parent environment into generated client fragments or detached
projection workers. Doctor checks never return environment values. The live viewer binds to
loopback, uses an unguessable URL token, supports read-only methods, and serves no arbitrary
filesystem tree.
Project secrets must not be placed in canonical documentation, adapter configuration, compiler
databases, templates, or changesets. Repository release gates include secret scanning, but that
scan is not a substitute for credential hygiene.
## No-AST boundary
`--no-ast` is a binding policy that preserves the selected adapter and prohibits Logic publication
and retrieval. It is not a parser detector, filesystem sandbox, or promise that unrelated
processes cannot parse source. See [legacy and no-AST operation](LEGACY_AND_NO_AST.md).
## Reporting and recovery
Do not bypass a confinement, identity, policy, hash, or limit error. Preserve the failing evidence,
stop the affected binding, and follow [recovery and performance](RECOVERY_AND_PERFORMANCE.md).