Skip to content

Releases

Sentryward 0.4.0

Choose a tag to compare

@rdlugs rdlugs released this 06 Nov 17:05
bd61c81

Sentryward remains pre-1.0, and this release changes some default behaviour:
adding someone to a team now sends them an invitation to accept, and
invite-only registration accepts fewer team invites. AI findings still need
human verification.

Upgrade notes

  • Back up the database and ENCRYPTION_KEY before upgrading. The server
    applies this release's migrations on start.
  • Adding a team member by email now creates an invitation the recipient must
    accept, and the add-member account picker is hidden. To restore immediate
    additions, an instance admin turns on Allow direct member additions
    under Administration > Instance settings > Policy. It is off on upgraded
    installations too; existing memberships are unaffected.
    GET /api/workspaces/:id/member-candidates answers 403 while it is off, and
    POST /api/workspaces/:id/members returns { invite, link, emailed }
    instead of { member }.
  • In invite-only mode, a team invite only creates new accounts when its
    creator is currently an instance admin. Reissue other outstanding invites
    from an admin, or use an instance invite.
  • WORKER_SHUTDOWN_DRAIN_MS (default 10 minutes) sets how long a stopping
    worker waits for in-flight reviews before handing them back to the queue.
    Keep WORKER_STOP_GRACE_PERIOD a few minutes above it (the defaults, 10m
    and 15m, already are), or Compose kills the worker before the hand-back.

Added

  • The LLM Config tab shows what was detected for the model that will run the
    review (thinking and tool support), and a Test model button runs it on that
    connection without saving. Connections whose key was rejected, could not be
    verified, or are blocked are marked in the connection picker (#190).
  • Fallback models can be moved up and down (#191).
  • The LLM Config tab shows the model's price, with a link to set one when it is
    unknown, and what an auto context budget resolves to for the model, max
    output tokens and thinking level, warning when a typed budget leaves no room
    for the reply. GET /api/config/schema now also returns the context windows
    and thinking budgets, and GET /api/settings/model-prices/lookup?model=
    returns the price a review of any model gets (#192).
  • The Triggers tab can check a sample change, under a Will this be reviewed?
    toggle that starts closed: an event, title, author, labels,
    branches and draft state are run through the worker's own skip rules with
    the unsaved settings, and it answers Reviewed (with or without the PR
    summary, every file or new commits only) or the reason it would be skipped.
    It is served by the new POST /api/config/triggers/check.
  • The header links to the GitHub repository beside the theme picker.

Changed

  • The verification model and verification thinking are greyed out while
    Verify findings is off, and the walkthrough model while the walkthrough is
    off, with a link to the tab that turns them on. Saved values are kept (#193).
  • LLM Config tab polish: effective values are only shown when they come from
    somewhere other than the scope being edited, Profile sits above the tabs
    since it applies to all of them, Connection capabilities overrides are under
    an Advanced disclosure (kept open while one is set), Reset to defaults
    explains what it keeps and why it may be disabled, and the Model,
    Temperature, Max output tokens and Context budget descriptions match what
    the server does (#194).
  • The Finding Types tab is regrouped into Severity, What gets reported,
    Accuracy, Scope and context, Static analysis and Fixes, with a summary panel
    beside it showing what a review reports and blocks on, unsaved edits
    included. A severity scale labels each severity as blocking, reported or
    hidden, and warns when the block level sits under the report level (those
    findings are dropped before they can block). Caller depth is greyed out
    while Surrounding code is off, and the agent limits unless Review context is
    Agentic. Categories have descriptions, a count and All/None buttons, and Min
    confidence has a slider. On every tab, a field's effective value now sits
    beside its label and the "leave empty" hint moved behind an info icon.
  • The Triggers tab is regrouped into Automatic reviews, PR summary, Commands
    and replies, and Skip rules (by change, people and branches), with a summary
    panel of when Sentryward runs, unsaved edits included. While automatic
    reviews are Manual only, the push switches, the PR summary trigger and the
    skip rules are greyed out, since the worker never reaches them; the PR
    summary trigger is also greyed out while the walkthrough is off, with a link
    to the Display tab. Each skip list is tagged with how it matches, the review
    trigger spells out what happens to drafts, and a repository's list says it
    replaces the inherited one.
  • Team membership requires consent. Adding someone by email creates an
    email-bound invitation (emailed when SMTP is configured, otherwise a link to
    copy), and access begins only when they accept. Team admins no longer see
    which emails have accounts, unless an instance admin turns on Allow direct
    member additions, which brings back the account picker and immediate
    additions (#206).
  • Stopping or upgrading the worker no longer leaves unfinished reviews waiting
    for stale-lock recovery. The worker waits up to WORKER_SHUTDOWN_DRAIN_MS
    for in-flight reviews, then puts any still running back in the queue without
    using one of their attempts, so the new worker picks them up about half a
    minute later. Each handed-back review stays leased until any forge call the
    old worker had in flight has finished, so it cannot be run twice (#212).

Fixed

  • Invite-only registration now requires an instance invite or a team invite
    whose original creator is currently an instance admin. Other team invites
    still let existing accounts join, but cannot create new accounts. Demoting
    or deleting the creator removes a team invite's registration authority;
    resending does not grant it (#205).
  • Logging in with an unknown email runs the same argon2 work as a wrong
    password, so response time no longer reveals whether an email has an
    account. Registration still answers 409 for a taken email, by design (#208).
  • Audit log export filenames use the viewer's local date instead of UTC (#214).
  • When two registrations race for the same email, the one that loses gets the
    usual 409 email field error instead of a server error.
  • The SSRF guard refuses reserved IPv4 ranges and IPv6 addresses that carry
    an internal IPv4 address (IPv4-mapped, NAT64 and 6to4), classified by the
    address they carry. Local-only mode keeps its previous list of internal
    addresses, so it does not start trusting public hosts reached through those
    ranges (#207).
  • The agentic search_code tool on GitHub sends the model's term as one
    quoted phrase, so search qualifiers in it (such as repo: or org:) can no
    longer point the search at other repositories. An empty term finds nothing
    instead of failing the caller search (#211).
  • Turning reviews on for a repository twice at once, or after a forge request
    that timed out, no longer leaves a duplicate or orphaned webhook. The
    registration is reconciled with the forge's existing hooks by URL, and a
    hook created for a repository removed meanwhile is deleted.
  • timeAgo rounds values that reach a full unit up to that unit instead of
    showing "60 minutes ago" or "24 hours ago", and past and future times now
    round halfway values the same way (90 seconds ago reads "2 minutes ago")
    (#213).
  • The worker's forge cache can no longer grow without bound on large changes.
    It was limited to 200 entries whatever their size, so a few big monorepo
    pull or merge requests (whole file lists with patches, or full files) could
    push the worker toward running out of memory. Cached entries now also stay
    under 64 MB in total, and a single answer over 8 MB is used for the review
    but not cached. Closes #188.
  • Renewing a GitLab OAuth connection's access can no longer lose the tokens
    GitLab issued. If the refresh transaction timed out or failed to commit after
    GitLab answered, the new tokens were rolled back while the old refresh token
    was already spent, and the connection needed a manual reconnect. The token
    request is now capped to the time the transaction has left, and tokens from a
    refresh whose transaction fails are still stored, unless the connection was
    updated in the meantime (#187).
  • A review whose worker stalled past the lock timeout, and was retried by
    another worker, can no longer finish or fail the retry when it wakes up.
    Finishing and failing a job now apply only to the attempt that holds it, so
    the retry's result and findings are stored instead of being dropped.
    Closes #185.
  • A pull or merge request that is closed and then reopened without a new push
    is reviewed again. The review cancelled by the close no longer counts as one
    already done for that head, so the reopen webhook queues it instead of
    answering duplicate. Closes #184.
  • A forge that accepts the connection but never answers no longer hangs a
    review or a webhook. Every forge API request, including each redirect hop,
    is now aborted after 30 seconds, so the worker fails the run and frees it
    instead of keeping the whole change in memory, and webhook handlers that
    call the forge respond. Closes #186.
  • Two reviews of the same pull or merge request no longer run at the same
    time. A newer push now waits for the running review to finish, so an older
    head that finishes last can no longer overwrite the newer review's summary
    comment, reopen its fixed findings or become the latest review. A review
    cancelled from the dashboard or stopped by the run time limit finishes
    stopping before the next one starts, and if a worker dies mid-review the next
    review of that change starts within about three heartbeats (3 minutes by
    default). Close...
Read more

Sentryward 0.3.0

Choose a tag to compare

@rdlugs rdlugs released this 31 Oct 16:06
a563b64

Sentryward remains pre-1.0, and this release changes some default behaviour:
review context now follows callers two hops from the changed code, and
changing your password signs out your other sessions. AI findings still need
human verification.

Upgrade notes

  • Back up the database and ENCRYPTION_KEY before upgrading. The server
    applies this release's migrations on start.
  • review.impact_depth defaults to 2, so reviews search for callers of
    callers (within a cap of 8 code searches per review). Set
    review.impact_depth: 1 to keep the previous context.
  • REVIEW_RETENTION_DAYS is optional and unset keeps everything, as before.
    Once a retention period is set (here or under Instance settings), the worker
    deletes and clears older review data hourly, including the findings of
    changes with no activity in that period.
  • GET /api/usage no longer returns recent; API clients that read it should
    use GET /api/usage/recent.

Added

  • list_dir tool for agentic review passes (#144). With
    review.context: agentic, a pass can now list a directory at the change's
    head revision on GitHub and GitLab, e.g. to find a changed file's tests or
    siblings. Paths follow read_file's rules (relative, no ..), directories
    end in / and symlinks in @, a listing shows at most 50 entries, and its
    output is marked as untrusted and counted against the pass's tool budget.
    A directory larger than the forge returns in one request (100 entries on
    GitLab, 1000 on GitHub) is reported as incomplete rather than given a wrong
    count. Listings are cached by head sha like file reads.
  • Phone layout for the Reviews and Findings lists (#165). Below 640px wide
    (phones, or high browser zoom) each review and finding is a stacked card
    instead of a table row, so the lists reflow at 320px without scrolling
    sideways. Cards keep every column's value, the row menu and click-anywhere
    to open; a review's earlier runs expand inside its card, and a finding's
    change title is written out rather than left in a tooltip. Findings get a
    "Sort by" picker and a direction toggle in place of the sortable headers.
    Long active-filter chips truncate instead of widening the page, and the
    pagination's "Rows per page" label reads "Rows" on phones so its controls
    wrap.
  • Command palette and a global "Review a PR" action (#161). Ctrl+K (Cmd+K
    on macOS, where plain Ctrl+K stays the text fields' "delete to end of
    line") opens and closes a palette from any dashboard page, also from the top
    bar's Search button: it jumps to any page (admin pages only for admins, plus
    Settings), lists repositories and opens a repository's reviews, starts a
    manual review, and queues a review for a pasted pull or merge request link.
    It does not open over another dialog, sheet or menu, says when repositories
    are still loading or could not be loaded, and closing it while a link is
    being queued leaves you on the page with a "Review queued" toast to open it.
    A "Review a PR" button in the top bar opens the manual review sheet from
    every page; Home and Reviews open that same sheet.
  • Keyboard navigation and severity jump for findings on the review page
    (#157). Ctrl+J/Ctrl+U move between findings in display order, Ctrl+O
    or Enter expands or collapses the focused one, Ctrl+C copies its agent
    prompt (or the selected text, when there is a selection), and Ctrl+? opens
    a dialog listing the shortcuts. Shortcuts are ignored while typing in a
    field and inside menus and dialogs, and Cmd is left to the browser. A sticky
    "Jump to" bar under the header shows per-severity counts of the visible
    findings and focuses the first finding of a severity; it also opens the
    shortcuts dialog. Focus from the keyboard, a jump, Tab or a click shares one
    position, and the focus ring stays visible after a mouse-started jump.
    Ctrl+O and Ctrl+C only act while a finding has focus, a shortcut with
    nothing to act on is left to the browser (so its own Ctrl+J and Ctrl+O
    still work, while Ctrl+U never opens view source on the review page),
    Ctrl+? follows the active keyboard layout, and a jump clears the bar even
    when it wraps on narrow screens.
  • Key metrics on Home (#154). Once the workspace has a review, Home shows
    four tiles above the setup checklist: open critical/major findings, reviews
    and failed runs in the last 7 days, and estimated spend over the last 30
    days. Each links to the matching list (open findings sorted worst first,
    runs, failed runs, Usage on the 30-day window), loads with its own skeleton,
    and shows "-" if its stats fail to load. Stat takes a linkLabel so a
    linked tile can name the page it opens.
  • Progress for running reviews (#156). The worker records the current stage
    on the job (new progress column on review_jobs): fetching the change,
    preparing, reviewing (with n of m passes, and planning, context and
    walkthrough as details), checking findings and publishing, listing only the
    steps the run's config turns on. GET /api/reviews/:id returns it, and the
    review page shows a step list with elapsed time instead of a single spinner
    line (queued reviews show how long they have waited, and a job requeued
    after its worker stopped says it is waiting to retry). Until the run's
    config is known only the current step is listed, so the list only grows.
    Writes are best effort, coalesced, and only made by the attempt that holds
    the job; a new claim clears them, and every run waits for its last write
    before returning.
  • Privacy controls (#109). A new "Privacy and data" section of the README
    lists what Sentryward stores, what is sent to model providers and forges,
    and how long it is kept. Instance admins get an Instance settings page
    (GET/PUT /api/admin/settings, new instance_settings table) and
    workspace admins a Privacy page (GET/PUT /api/privacy, new
    workspace_privacy table) to restrict model requests to chosen providers
    and hosts (exact names, *.example.com wildcards, optional ports) or to
    local endpoints only (hosts that resolve to private or loopback addresses).
    A workspace can only narrow the instance policy. The policy is checked
    before a review posts anything, for every model it may call, including
    ones named in .sentryward.yaml: a refused review, walkthrough or verify
    model fails the review with a Blocked by privacy policy: reason, a
    refused fallback is skipped with a warning, thread answers post a short
    notice instead, and LLM connection save, test and model-list requests to
    a refused host are rejected before they are sent (the connection shows as
    "Blocked by policy"). Retention is now configurable from the dashboard
    (instance period, falling back to REVIEW_RETENTION_DAYS, which workspaces
    can shorten) and also purges the findings, posted-comment records and
    finished thread replies of changes with no activity for longer than the
    period. Every outbound model request (reviews, walkthroughs, verification,
    capability probes, thread answers and connection tests) is recorded in a
    new llm_request_logs audit table with its workspace, repository,
    purpose, provider, host, model, token counts, latency and outcome, never
    prompts, code or error text. Admins can browse, filter and export it as
    CSV or JSON on the Privacy page (/api/privacy/audit-log) and, for every
    workspace, in the Audit log tab of Instance settings
    (/api/admin/audit-log), and an instance audit retention period removes
    old entries.
  • Cross-file impact analysis (#108). Review context now follows callers of
    changed code more than one hop (review.impact_depth, 1-3, default 2, 1 in
    the fast profile; also in the dashboard under Findings > Review context):
    each caller's enclosing function becomes the next name searched, within a
    shared cap of 8 code searches per review (generic method names such as
    run or handle are not traced), and further hops are the first context
    dropped when a pass is out of room. Callers of declarations the diff
    changes or removes, including parameters on later lines of a multi-line
    signature, are searched first and labelled signature changed /
    removed, and the review prompt asks for broken contracts to be reported
    with evidence: contract, the affected callers in impact and their files
    in evidenceFiles, which the summary and inline comments show as
    Affected for contract findings. The walkthrough lists risky areas
    (authorization checks, database writes and schema changes, API routes, and
    route handlers or auth modules reached through callers; test files never
    count) in the summary comment and the dashboard's walkthrough card, both
    hidden by output.walkthrough_blast_radius, and they raise its blast
    radius: at least medium for any risky area, large only for a removed
    auth check. Reviews stored before review.impact_depth existed still allow
    an incremental review on the next push.
  • Model and review-cost benchmarking (#107). Workspace admins can set their
    own model prices under LLM Connections > Model prices (GET/PUT /api/settings/model-prices, DELETE /api/settings/model-prices/:id,
    new model_prices table); a review's calls are priced at them when it
    runs, ahead of the built-in table. A model nothing prices now records no
    cost and is flagged unpriced, so its cost reads as unknown instead of $0
    on the Usage page (totals, table and recent reviews), the Reviews stats
    strip and the review sidebar; the digest's usageTotals, review stats
    tokens and recent usage rows carry unpricedCalls for it. Ollama models
    stay free unless priced. A workspace price keyed by any prefix-stripped
    form of a router id (cx/gpt-5.6-sol for openai/cx/gpt-5.6-sol) applies,
    and the price list's models carry the price reviews get now, so the
    "no price" warning clears for them. A saved price's model id can't be
    changed...
Read more