Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
338b3cc
fix(clearfolio): fail closed when production is unconfigured
seonghobae Aug 14, 2026
9f223d9
test(clearfolio): prove explicit development and production config bo…
seonghobae Aug 14, 2026
6f9985c
test(clearfolio): enforce signed production and token-origin boundaries
seonghobae Aug 14, 2026
d330ff6
fix(clearfolio): bind viewer tokens to their returned origin
seonghobae Aug 14, 2026
4721551
test(clearfolio): make attachment mock mode explicit
seonghobae Aug 14, 2026
4632000
docs(deploy): make Clearfolio production readiness explicit
seonghobae Aug 14, 2026
45808bf
docs(doctoring): record Clearfolio fail-closed configuration evidence
seonghobae Aug 14, 2026
3facf19
docs(changelog): record Clearfolio production config boundary
seonghobae Aug 14, 2026
928782c
test(clearfolio): cover malformed provider origins
seonghobae Aug 14, 2026
3eecbde
test(clearfolio): cover same-origin viewer token translation
seonghobae Aug 14, 2026
90bd672
test(clearfolio): require 32 non-whitespace HMAC characters
seonghobae Aug 14, 2026
e46dd51
test(clearfolio): prove internal whitespace cannot satisfy secret length
seonghobae Aug 14, 2026
c8da068
fix(clearfolio): count only non-whitespace secret characters
seonghobae Aug 14, 2026
516429f
test(clearfolio): cover IPv6 loopback development URL
seonghobae Aug 14, 2026
5062a8d
fix(clearfolio): recognize IPv6 loopback URL hostname
seonghobae Aug 14, 2026
6cbfc82
merge(clearfolio): reconcile production configuration with protected …
seonghobae Aug 16, 2026
4953fba
test(clearfolio): reject cross-origin artifact tokens
seonghobae Aug 16, 2026
b66180d
fix(clearfolio): reject cross-origin artifact tokens
seonghobae Aug 16, 2026
3834cf2
docs(clearfolio): record fail-closed cross-origin token rule
seonghobae Aug 16, 2026
484dbc0
merge(clearfolio): reconcile protected XML import baseline
seonghobae Aug 16, 2026
d122ca7
docs(deploy): align orchestrator fail-closed contract
seonghobae Aug 16, 2026
5c2f73d
fix(clearfolio): fail closed on provider redirects and unreviewed hosts
cursoragent Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@
contain.
- Kubernetes/IaC security coverage remains a follow-up design lane for
any future `infra/` or container packaging surface.
- Clearfolio is an optional production capability. The in-memory adapter
exists only under `SCOPEWEAVE_DEV=1` with no provider URL. Production
conversion fails closed when unconfigured, refuses provider redirects
that would replay tenant HMAC headers, and accepts artifact links only
from the configured Clearfolio origin until a reviewed host allowlist
exists. See `docs/doctoring/clearfolio-production-configuration.md`.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security

- Made contextual-orchestrator briefing requests fail closed unless an authenticated endpoint is configured. Deterministic generated text is restricted to explicit `SCOPEWEAVE_DEV=1`, message/provider responses are bounded and validated, and non-loopback HTTP transport is rejected.
- Confined the in-memory Clearfolio adapter to explicit development mode,
required a canonical signed production origin, rejected ambiguous provider
URL components, refused provider HTTP redirects so tenant HMAC headers
cannot follow a `Location`, and rejected cross-origin, credentialed, or
fragmented artifact links instead of transplanting tokens or issuing an
unreviewed attachment-view 302.
- Made `SCOPEWEAVE_JWT_SECRET` mandatory at startup and rejected weak or
unexpanded placeholder values so production deployments fail closed.
- Neutralized audit-log CSV formulas even when executable prefixes are hidden
Expand Down
27 changes: 22 additions & 5 deletions docs/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,35 @@ persists the database in the `scopeweave-data` volume.
| `SCOPEWEAVE_JWT_SECRET` | **yes** | Signs session JWTs. Startup fails unless it contains at least 32 non-whitespace characters. |
| `PORT` | no (default 8787) | Listen port |
| `SCOPEWEAVE_DB` | no (default `/data/scopeweave.db`) | SQLite file path (on the volume) |
| `SCOPEWEAVE_DEV` | no | Must be `1` to enable the dev `activate-pro` endpoint. **Never set in production.** |
| `SCOPEWEAVE_DEV` | no | Must be `1` to enable development-only behavior, including `activate-pro`, deterministic orchestrator responses, loopback Clearfolio HTTP, and the in-memory Clearfolio adapter when no provider URL exists. **Never set in production.** |
| `STRIPE_SECRET_KEY`, `STRIPE_PRICE_ID`, `STRIPE_WEBHOOK_SECRET` | for live billing | Enables real Stripe Checkout (`npm i stripe` too). Without them, billing uses the mock path. |
| `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`, `OIDC_REDIRECT_URI` | for real SSO | Points the OIDC login at your IdP. Unset → a built-in mock IdP (dev/test only). |
| `ORCHESTRATOR_URL` | for AI 브리핑 | contextual-orchestrator 주소. Unset → deterministic mock. |
| `ORCHESTRATOR_TOKEN` | with URL | orchestrator Bearer 토큰 (`CONTEXTUAL_ORCHESTRATOR_TOKEN`). |
| `CLEARFOLIO_URL` | for 산출물 viewer | Clearfolio 문서 뷰어 백엔드 주소. Unset → built-in mock (dev/test). |
| `CLEARFOLIO_HMAC_SECRET` | optional | Signs tenant-claim headers (`clearfolio.tenant-claims.hmac-secret`와 동일 값). |
| `ORCHESTRATOR_URL` | for production AI briefing | Root contextual-orchestrator service origin. Production briefing fails closed when it is absent; deterministic responses exist only with `SCOPEWEAVE_DEV=1`. |
| `ORCHESTRATOR_TOKEN` | with URL | Required bearer token for the configured contextual-orchestrator service (`CONTEXTUAL_ORCHESTRATOR_TOKEN`). |
| `CLEARFOLIO_URL` | for production 산출물 viewer | Root Clearfolio service origin. Production requires HTTPS and rejects credentials, paths, query strings, and fragments. When absent in production, document conversion/viewing is unavailable rather than simulated. |
| `CLEARFOLIO_HMAC_SECRET` | with URL | Required tenant-claim HMAC secret; must contain at least 32 non-whitespace characters and match Clearfolio's configured verifier secret. |
| `SCOPEWEAVE_ATTACHMENT_STATUS_CONCURRENCY` | no (default 8, maximum 32) | Maximum concurrent Clearfolio status lookups during one attachment-list request. Invalid values fall back to 8; values above 32 are clamped. |
| `SCOPEWEAVE_ATTACHMENT_STATUS_TIMEOUT_MS` | no (default 3000, maximum 30000) | Hard caller-side timeout for each Clearfolio status lookup. The AbortSignal is also forwarded downstream. |
| `SCOPEWEAVE_ATTACHMENT_STATUS_BUDGET_MS` | no (default 5000, maximum 60000) | Wall-clock budget for the entire best-effort refresh pass. Work not started before the deadline is deferred to a later list request. |
| `SCOPEWEAVE_RATE_LIMIT_MAX` (+ `SCOPEWEAVE_RATE_LIMIT_WINDOW_MS`) | recommended | Per-IP fixed-window rate limiting (429 + Retry-After). Off when unset. |

### Clearfolio capability readiness

An unset `CLEARFOLIO_URL` is not a successful production conversion service.
Outside explicit `SCOPEWEAVE_DEV=1`, Clearfolio operations fail closed with a
stable configuration error and the mock artifact route is not registered. Other
ScopeWeave planning capabilities remain available. For local integration work,
`SCOPEWEAVE_DEV=1` permits the in-memory adapter when the URL is absent and also
permits HTTP only for `localhost`, `127.0.0.1`, or `[::1]`; remote HTTP endpoints
are rejected. Provider `fetch` calls fail closed on HTTP redirects so tenant HMAC
headers are never replayed onto another host. Attachment-view links must share
the configured Clearfolio origin until a reviewed artifact-host allowlist exists.

Provider URLs are treated as service origins, not arbitrary request prefixes.
Keep credentials in the dedicated HMAC secret setting rather than URL userinfo,
and do not configure a path, query string, or fragment. The adapter constructs
its own versioned API paths from the validated origin.

## Attachment status refresh operations

The attachment-list API reads `job_id` in its initial project-scoped query and
Expand Down
54 changes: 54 additions & 0 deletions docs/doctoring/clearfolio-production-configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Clearfolio production configuration boundary

## Decision

ScopeWeave treats Clearfolio as an optional production capability, not as an implicit successful mock. The in-memory converter is available only when `SCOPEWEAVE_DEV=1` and no provider URL is configured. Outside that explicit development boundary, an absent provider produces the stable `clearfolio_not_configured` failure and the mock artifact route is not registered.

A configured production provider must be a root HTTPS origin. ScopeWeave parses the operator value with the platform `URL` implementation and rejects URL credentials, query strings, fragments, and configured paths before building any downstream endpoint. HTTP is limited to explicit development mode on `localhost`, `127.0.0.1`, or `[::1]`. The tenant-claim HMAC secret is mandatory with a configured provider and must contain at least 32 non-whitespace characters. Surrounding whitespace, including a trailing newline from a secret file, is trimmed before length checking and signing so the adapter and Clearfolio verify the same key.

This boundary prevents configuration text from becoming an arbitrary downstream request prefix and prevents a production deployment from persisting fake `SUCCEEDED` conversion state merely because an integration is absent. It also preserves independent ScopeWeave operation: planning functionality remains available while document conversion/viewing fails closed with an actionable configuration error.

## Artifact-token origin rule

Returned artifact links must share the configured Clearfolio origin. Same-origin `artifactToken` values are rewritten into the trusted Clearfolio viewer route. A cross-origin link — with or without a token — is rejected rather than transplanted into the trusted viewer or returned through the attachment-view 302. Credentials and fragments on the returned link are also rejected. This fail-closed default does not invent a CDN allowlist; operators who later need object-storage hosts must land an explicit reviewed allowlist in a later #489 slice.

## Provider redirect rule

Clearfolio submit, status, and artifact-link `fetch` calls set `redirect: 'error'`. The Fetch default follows redirects and would replay tenant HMAC headers onto a `Location` host because those headers are not forbidden. A 3xx from the pinned origin therefore fails closed with the existing sanitized transport error instead of leaking tenant, subject, permissions, issued-at, or the signature.

Issue #489 remains open after this slice. A subsequent bounded change must still implement the explicit reviewed artifact-origin allowlist, streaming response-size/media-type limits, provider-wide request budget, and the remaining resource/lifecycle acceptance criteria before the Clearfolio adapter can be described as fully production-complete.

## Executable evidence

`tests/unit/clearfolio-adapter-mock-hmac.test.mjs` proves:

- production without `CLEARFOLIO_URL` does not enable the mock and fails submit/status/artifact operations closed;
- the mock works only under explicit `SCOPEWEAVE_DEV=1`;
- unsupported schemes, remote HTTP (including under `SCOPEWEAVE_DEV=1`), URL credentials, query strings, fragments, configured paths, and weak HMAC secrets are rejected;
- loopback HTTP is accepted only under explicit development mode;
- a secret-file trailing newline is trimmed before HMAC signing; and
- signed tenant headers retain the documented canonical HMAC contract and set `redirect: 'error'`.

`tests/unit/clearfolio-status-signal.test.mjs` continues to exercise sanitized transport/HTTP/JSON/status/artifact failures and now proves that a redirect `TypeError`, a token-bearing or token-free cross-origin artifact link, a protocol-relative host, and credentialed or fragmented same-origin links fail closed rather than moving a token into the Clearfolio viewer or returning an unreviewed 302 target. `tests/api/attachment-status.test.mjs` makes its test-only in-memory provider explicit instead of relying on an unset production URL.

The shipped `server/clearfolio.mjs` remains in the canonical c8 production coverage target, so the new configuration branches execute under the repository coverage gate rather than a documentation-only path.

## Standards and threat rationale

The WHATWG URL Standard defines URL components, including credentials, queries, and fragments, and provides the common parsing model used by the JavaScript `URL` API. ScopeWeave parses first and then applies component-level policy instead of relying on string-prefix validation.

OWASP's SSRF Prevention guidance recommends strict allowlisting and warns that redirects and attacker-controlled complete URLs can bypass URL validation. This slice narrows operator configuration to a provider origin, keeps request paths adapter-owned, refuses to follow provider redirects, and refuses unreviewed artifact hosts. The remaining artifact-host allowlist, streaming body limits, and request-budget controls stay explicitly tracked by issue #489.

NIST SSDF 1.1 recommends identifying and maintaining software security requirements and producing well-secured software through repeatable verification. The fail-closed configuration contract, executable negative tests, and explicit remaining-gap statement provide acquisition-review evidence without claiming certification.

## Rollback

Rollback reverts the Clearfolio configuration parser, explicit development-mode tests, same-origin artifact rule, `redirect: 'error'` provider fetches, HMAC secret trimming, deployment text, this doctoring record, and the corresponding CHANGELOG entry together. No database schema or persisted attachment representation changes in this slice. After rollback, production again follows provider redirects with tenant HMAC headers and can 302 a browser to an unreviewed artifact host.

## References

National Institute of Standards and Technology. (2022). *Secure Software Development Framework (SSDF) Version 1.1: Recommendations for mitigating the risk of software vulnerabilities* (NIST Special Publication 800-218). https://doi.org/10.6028/NIST.SP.800-218

OWASP Foundation. (n.d.). *Server Side Request Forgery Prevention Cheat Sheet*. OWASP Cheat Sheet Series. https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html

WHATWG. (2026). *URL Standard*. https://url.spec.whatwg.org/
Loading
Loading