Skip to content

fix(review): require signed workspace authority - #165

Closed
seonghobae wants to merge 33 commits into
mainfrom
fix/review-trusted-workspace-authority
Closed

fix(review): require signed workspace authority#165
seonghobae wants to merge 33 commits into
mainfrom
fix/review-trusted-workspace-authority

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Security outcome

Remove the remaining Review API trust in a browser-selectable x-workspace-id. All workspace-scoped guided-review completion/history routes now require the short-lived signed life-os.workspace.v1 context before tenant identity reaches domain or persistence code.

Test-first sequence

The first commits add RED contracts before production code:

  • cryptographic boundary tests require a fresh signed context and reject stale, future, forged, or unverifiable evidence with bounded credential-free 401/503 problems;
  • a controller source contract forbids @Headers('x-workspace-id') and requireWorkspaceHeader, and requires all four workspace-scoped route families to bind the signed workspace/issued-at/signature headers.

Implementation

  • requireTrustedWorkspaceContext validates the existing UUIDv4 workspace invariant, canonical Unix seconds, 43-character base64url SHA-256 HMAC, minimum 32-byte verifier secret, 60-second maximum age, 5-second future skew, and constant-time digest comparison;
  • the three completion routes and completion-history route consume x-life-os-workspace-id, x-life-os-context-issued-at, and x-life-os-context-signature with REVIEW_GATEWAY_CONTEXT_SECRET;
  • path/body values remain object/event data only; persistence tenant predicates and immutable review evidence are unchanged;
  • malformed/forged context never reaches ReviewService and public errors remain bounded and credential-free.

Scope

This is a service-boundary hardening slice. It does not add gateway routing, cross-service database access, user-level review authorization beyond the existing workspace boundary, or change review ritual/scoring semantics. The public gateway must mint this context only after authenticated workspace resolution when Review is composed into the hosted path.

Verification

Merge only after the unchanged exact head passes Review tests/typecheck/build, repository CI, AppGuardrail, SAST Semgrep, Security Scan, Commercial Readiness, current review findings, and current-live-base compatibility without administrative bypass.

Summary by CodeRabbit

  • 변경 사항
    • 리뷰 완료 및 조회 요청이 서명된 워크스페이스 컨텍스트로 인증됩니다.
    • 워크스페이스 ID, 발급 시각, HMAC 서명을 함께 검증합니다.
    • 만료되었거나 미래 시각이거나 변조된 인증 정보는 거부됩니다.
    • 인증 컨텍스트가 유효하지 않거나 검증할 수 없는 경우 상황에 맞는 오류 응답이 제공됩니다.
    • 기존의 단순 워크스페이스 헤더 방식은 더 이상 지원되지 않습니다.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Review Service가 단순 x-workspace-id 헤더를 제거했습니다. 모든 리뷰 라우트는 발급 시각과 HMAC 서명이 포함된 workspace context를 검증합니다. 성공하면 검증된 workspace ID를 리뷰 서비스에 전달합니다.

Changes

서명된 workspace context 인증

Layer / File(s) Summary
HMAC context 검증 경계
apps/review-service/src/http-boundary.ts, apps/review-service/src/http-boundary.test.ts
requireTrustedWorkspaceContext가 secret, 헤더 형식, workspace ID, 발급 시각, HMAC 서명을 검증합니다. 실패 유형에 따라 401 또는 503 응답을 반환합니다. 경계 테스트는 만료, 미래 시각, 위조 서명, secret 길이 경계를 확인합니다.
리뷰 라우트 인증 연결
apps/review-service/src/main.ts, apps/review-service/src/main.test.ts
완료 및 조회 라우트가 서명된 context를 검증합니다. 검증된 workspace ID를 도메인 서비스에 전달합니다. 테스트가 HMAC context를 생성하고 환경 변수를 설정·복원합니다.
라우트 권한 위임 계약
apps/review-service/src/review-controller-authority.test.ts
네 개 리뷰 라우트가 허용된 context 헤더와 requireTrustedWorkspaceContext를 사용하는지 확인합니다. 유효한 요청의 workspace ID 전달과 거부 요청의 서비스 미호출을 검증합니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ReviewController
  participant requireTrustedWorkspaceContext
  participant ReviewService
  Client->>ReviewController: 서명된 workspace context와 리뷰 요청
  ReviewController->>requireTrustedWorkspaceContext: context 검증
  requireTrustedWorkspaceContext-->>ReviewController: 검증된 workspace ID
  ReviewController->>ReviewService: workspace ID와 리뷰 작업 전달
  ReviewService-->>ReviewController: 처리 결과 반환
Loading

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.54% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 Review API에 서명된 workspace 권한을 요구하도록 변경한 PR의 주요 내용을 정확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/review-trusted-workspace-authority

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread apps/review-service/src/http-boundary.test.ts Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/review-service/src/http-boundary.test.ts (1)

49-89: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

허용된 시간 경계도 테스트하십시오.

현재 테스트는 NOW_SECONDS - 61NOW_SECONDS + 6만 거부합니다. MAXIMUM_CONTEXT_AGE_SECONDS의 정확히 60초 경계와 MAXIMUM_FUTURE_SKEW_SECONDS의 정확히 5초 경계가 허용되는지 검증하십시오.

경계값 테스트 예시
+  it.each([
+    String(NOW_SECONDS - 60),
+    String(NOW_SECONDS + 5),
+  ])('accepts a context at an allowed time boundary', (issuedAt) => {
+    expect(
+      requireTrustedWorkspaceContext(
+        { workspaceId: WORKSPACE_ID, issuedAt, signature: signature(issuedAt) },
+        SECRET,
+        NOW_SECONDS,
+      ),
+    ).toBe(WORKSPACE_ID);
+  });

As per coding guidelines, Tests must prove realistic domain accuracy and failure behavior, not only mocked call counts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/review-service/src/http-boundary.test.ts` around lines 49 - 89, Extend
the parameterized cases in the HTTP boundary test to cover the exact allowed
limits: issuedAt at NOW_SECONDS - 60 and NOW_SECONDS + 5 must be accepted with a
successful response and valid gateway-context result. Keep the existing
rejection cases for -61 and +6, and reuse the normal SECRET and signature setup
so the tests validate the real boundary behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/review-service/src/http-boundary.ts`:
- Around line 48-54: Add explanatory production-contract docstrings at
apps/review-service/src/http-boundary.ts:48-54 for invalidGatewayContext’s 401
status and safe error contract, at
apps/review-service/src/http-boundary.ts:56-62 for unavailableGatewayContext’s
HTTP status and configuration-failure meaning, and at
apps/review-service/src/http-boundary.ts:64-72 for workspaceContextDigest’s
canonical payload and digest format; also document at
apps/review-service/src/main.ts:111-117 that complete accepts only workspace IDs
that passed requireTrustedWorkspaceContext.

---

Nitpick comments:
In `@apps/review-service/src/http-boundary.test.ts`:
- Around line 49-89: Extend the parameterized cases in the HTTP boundary test to
cover the exact allowed limits: issuedAt at NOW_SECONDS - 60 and NOW_SECONDS + 5
must be accepted with a successful response and valid gateway-context result.
Keep the existing rejection cases for -61 and +6, and reuse the normal SECRET
and signature setup so the tests validate the real boundary behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dd4ae884-8179-4d8a-b3e4-2971c43445a7

📥 Commits

Reviewing files that changed from the base of the PR and between 563fa98 and c53ead9.

📒 Files selected for processing (5)
  • apps/review-service/src/http-boundary.test.ts
  • apps/review-service/src/http-boundary.ts
  • apps/review-service/src/main.test.ts
  • apps/review-service/src/main.ts
  • apps/review-service/src/review-controller-authority.test.ts

Comment thread apps/review-service/src/http-boundary.ts
@seonghobae seonghobae closed this Aug 10, 2026
@seonghobae seonghobae reopened this Aug 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/review-service/src/review-controller-authority.test.ts`:
- Around line 152-158: Update the RouteCase definitions and success-path loop in
the review-controller authority tests to include realistic request bodies,
complete expected service arguments, and expected return values for each route.
Assert the exact arguments passed through route.invoke—including complete’s
ritualKind/body and list’s limit—and verify the returned value, while preserving
the existing call-count assertion.
- Around line 175-180: Extend the invalidContexts cases in the review-controller
authority tests to cover contexts missing issuedAt and signature, asserting each
returns 401 and does not invoke the domain service. Keep the existing
missing-workspaceId, expiration, tampering, malformed, and unconfigured-secret
cases unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7f29f20c-66e0-404b-9da0-3a67806bd050

📥 Commits

Reviewing files that changed from the base of the PR and between f76888b and b929135.

📒 Files selected for processing (2)
  • apps/review-service/src/http-boundary.test.ts
  • apps/review-service/src/review-controller-authority.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/review-service/src/http-boundary.test.ts

Comment thread apps/review-service/src/review-controller-authority.test.ts Outdated
Comment thread apps/review-service/src/review-controller-authority.test.ts Outdated

Copy link
Copy Markdown
Contributor Author

Superseded by #178. The #165 branch acquired a GitHub Actions-authored main-merge head whose PR workflows ended action_required with zero jobs. #178 was reconstructed from current protected main and preserves the same five Review-path semantic blobs without transferring predecessor checks/reviews.

Copy link
Copy Markdown
Contributor Author

Superseded by clean current-main successor #178. The successor preserves the exact five Review authority paths from this branch, starts from current protected main, and requires fresh exact-head CI/security/review evidence; no predecessor checks or approvals transfer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants