Appearance
Create a review on a rule (comment, request_review, etc.)
POST
/rules/{ruleId}/reviews
Posts a new comment or review action on the specified rule. Requires viewer role or above on the component.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "review": { "action": "comment", "comment": "The fix text should reference the container runtime configuration file.", "section": "fixtext", "responding_to_review_id": 43 }
{
}
Responses
Review created
application/json
JSON "toast": { "title": "User updated.", "message": [ [ "Successfully updated user." ] ], "variant": "success" }
{
}
Post a public comment on a component
POST
/components/{componentId}/reviews
Creates a new comment-action review on the component (component-level comment) or on a specific rule within it. The component must have an open comment period (accepting_new_comments? check). Requires project membership with at least viewer role.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "review": { "action": "comment", "comment": "The overall approach to container isolation is sound.", "section": null }
{
}
Responses
Comment created
application/json
JSON "toast": { "title": "Comment posted.", "message": [ "Your comment has been submitted for review." ], "variant": "success" }
{
}
Triage multiple reviews at once
PATCH
/reviews/bulk_triage
Applies the same triage status to all specified reviews in a single request. Parameters are FLAT (no wrapper object). All reviews must belong to the same component (enforced server-side). Terminal statuses (duplicate, informational, withdrawn, addressed_by) auto-adjudicate every selected review. Conditional requirements: non_concur requires response_comment; duplicate requires duplicate_of_review_id; addressed_by requires addressed_by_rule_id. The target is ONE shared value applied to every selected review — many comments duplicating one canonical thread, or addressed by one rule. A duplicate canonical that is itself among review_ids is rejected. Every per-comment validator runs per selected review (same-component canonical, no chained duplicates); any failing review rolls back the whole batch. Optionally creates a response comment on each triaged review. Requires author+ role on the component's project.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "review_ids": [ 10, 11, 12 ], "triage_status": "concur"
{
}
Responses
All reviews triaged successfully
application/json
JSON "reviews": [ { "id": 10, "action": "comment", "comment": "Original comment 1", "triage_status": "concur", "rule_id": 100, "created_at": "2026-05-19 14:08:17 UTC", "reactions": { "up": 0, "down": 0, "mine": null } } ], "response_reviews": [ ]
{
}
Merge duplicate reviews into one survivor
PATCH
/reviews/merge
Combines multiple same-author reviews within one component into a designated survivor. Non-survivor reviews are marked as duplicates (triage_status=duplicate, duplicate_of_review_id=survivor). Requires admin role on the component's project.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "review_ids": [ [ 10, 11, 12 ] ], "survivor_id": 10
{
}
Responses
Reviews merged successfully
application/json
JSON "survivor": { "id": 10, "action": "comment", "comment": "The original comment", "triage_status": "pending", "rule_id": 100, "created_at": "2026-05-19 14:08:17 UTC", "reactions": { "up": 0, "down": 0, "mine": null } }, "duplicates": [ { "id": 11, "action": "comment", "comment": "Duplicate of 10", "triage_status": "duplicate", "duplicate_of_review_id": 10, "rule_id": 100, "created_at": "2026-05-19 14:10:00 UTC", "reactions": { "up": 0, "down": 0, "mine": null } } ]
{
}
Update a review comment
PUT
/reviews/{reviewId}
Edits the comment text of an existing review. Only the original author or an admin can update.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "review": { "comment": "The fix text should reference the container runtime configuration file." }
{
}
Responses
Review updated
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Set triage status on a comment (concur, non_concur, etc.)
PATCH
/reviews/{reviewId}/triage
Assigns a triage decision to the comment. Parameters are FLAT (no wrapper object). Terminal statuses (duplicate, informational, withdrawn, addressed_by) auto-adjudicate. Submitting "pending" is rejected — it is the initial state, not a decision. Conditional requirements: non_concur requires response_comment; duplicate requires duplicate_of_review_id; addressed_by requires addressed_by_rule_id. Requires author or admin role.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "triage_status": "concur"
{
}
Responses
Triage status set
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }, "response_review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Adjudicate (close) a triaged comment
PATCH
/reviews/{reviewId}/adjudicate
Marks the comment as adjudicated, finalizing the triage decision. Requires author or admin role.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "resolution_comment": "Fix text updated in R2 — closing as concur."
{
}
Responses
Review adjudicated
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }, "response_review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Author withdraws their own comment
PATCH
/reviews/{reviewId}/withdraw
Allows the comment author to retract their comment. Sets triage_status to withdrawn and auto-adjudicates.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Responses
Review withdrawn
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Admin force-withdraws a comment
PATCH
/reviews/{reviewId}/admin_withdraw
Admin-only force withdrawal that bypasses the frozen-for-writes check. Requires an audit comment explaining the action.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "audit_comment": "Removing PII discovered after the comment window closed."
{
}
Responses
Review withdrawn by admin
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Admin restores an adjudicated comment to pending
PATCH
/reviews/{reviewId}/admin_restore
Inverse of admin_withdraw and any other adjudication — resets the comment to pending status so it can be re-triaged through the normal flow. Rejects comments that are not adjudicated (nothing to restore from). Requires admin role on the project and an audit comment explaining the action.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "audit_comment": "Restoring — the wrong comment was force-withdrawn."
{
}
Responses
Review restored
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Admin moves a comment thread to a different rule
PATCH
/reviews/{reviewId}/move_to_rule
Reassigns the comment and all its replies to a different requirement row in the same component. The target may be either document kind — a stig rule or an authored SRG requirement (the lookup spans both). Walks parent-first to satisfy validators and records an outbound audit entry on the source rule. Requires admin role.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "rule_id": 15117, "audit_comment": "Comment applies to the account-management requirement."
{
}
Responses
Review moved — returns the updated review.
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Admin permanently deletes a comment (irreversible)
DELETE
/reviews/{reviewId}/admin_destroy
Hard-deletes a comment and all its replies. Requires an audit comment explaining the action — the pre-destroy snapshot plus that comment become the audit record. (The web UI additionally asks the admin to type the comment ID to confirm; the API has no confirmation field.) This action cannot be undone.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "audit_comment": "Legal hard-delete — comment contained PII."
{
}
Responses
Review destroyed
application/json
JSON "review": null, "destroyed_id": 44
{
}
List replies to a review
GET
/reviews/{reviewId}/responses
Returns threaded replies to a parent review, ordered by creation time. Each reply is serialized via ReviewBlueprint with commenter attribution, reaction counts, and the current user's reaction.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Responses
Reply thread
application/json
JSON "rows": [ { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } } ]
{
}
Re-open an adjudicated review
PATCH
/reviews/{reviewId}/reopen
Reverts the adjudication on a closed review, clearing adjudicated_at and adjudicated_by_id so the triage decision can be revised. Requires author role or higher on the parent project. Returns 422 warning toast if the review has not been adjudicated or was withdrawn by the commenter.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Responses
Review re-opened
application/json
JSON "review": { "id": 1, "action": "comment", "comment": "The check says "verify that TLS 1.2 or greater is being used" but does not specify HOW to verify.", "created_at": "2026-05-19 14:08:17 UTC", "triage_status": "pending", "triage_set_at": "string", "adjudicated_at": "string", "rule_id": 2976, "section": "check_content", "responding_to_review_id": 0, "duplicate_of_review_id": 0, "addressed_by_rule_id": 0, "triage_set_by_id": 0, "name": "Demo Viewer", "author_name": "Demo Viewer", "triager_display_name": "string", "triager_imported": false, "adjudicator_display_name": "string", "adjudicator_imported": false, "commenter_display_name": "Demo Viewer", "commenter_imported": false, "commentable_type": "BaseRule", "responses_count": 0, "rule_displayed_name": "PHOS-03-000001", "author_email": "string", "commenter_email": "string", "reactions": { "up": 1, "down": 0, "mine": "string" } }
{
}
Update the section field on a review
PATCH
/reviews/{reviewId}/section
Changes which requirement section (fixtext, check_content, vuln_discussion, etc.) a comment addresses. Idempotent — re-saving the same section returns the review with an idempotent: true flag. Requires author role or higher. An audit trail entry is created for non-idempotent changes.
Authorizations
cookieAuth
Type
API Key (cookie: _vulcan_session)
or
tokenAuth
Personal access token authentication. Send via Authorization header: Authorization: Token vulcan_xxx. Tokens are SHA-256 hashed server-side (never stored in plaintext). Scopes: read (GET), write (mutations), admin (everything). Create tokens via Settings → API Tokens in the web UI.
Type
HTTP (token)
Request Body
application/json
JSON "section": "vuln_discussion", "audit_comment": "Re-categorized after author clarification."
{
}
Responses
Section updated (or idempotent no-op)
application/json
JSON "review": { "id": 44, "action": "comment", "comment": "This requirement needs clarification...", "rule_id": 812, "section": "vuln_discussion", "triage_status": "pending", "created_at": "2026-05-19T16:15:00Z", "reactions": { "up": 1, "down": 0 } }
{
}