Skip to content

v1.1.1

Choose a tag to compare

@github-actions github-actions released this 10 Oct 04:32
· 22 commits to main since this release
23c1da8

[1.1.1] - 2026-10-10

Security

  • Authorizing an HTTP MCP server no longer puts the PKCE verifier or the
    client secret in the authorization link: its state is now a random,
    single-use reference to the request, which stays on the server and
    expires after 10 minutes. A restart during consent means starting the
    authorization again.
  • When several globs in an MCP Skill match a tool, the strictest one now sets
    its policy whatever order they are written in; before, the first listed
    won, so a broad allow written first let a narrower blocked tool run. The
    generic command guard also catches runner names in any case or separator
    style (run-command, kubectl-exec, ExecuteCommand) and python_repl and
    code_interpreter. Review skills that relied on a broad glob listed first.
  • SAML and OIDC sign-in now refuse a deactivated account before signing it
    in, and change nothing about it. Before, the sign-in issued a token that
    was refused only on its first use.
  • WeCom and Weixin updates are checked against their signature before
    OpsMender decrypts or reads them, and a malformed body gets 400 instead of
    a server error. Before, WeCom updates were decrypted without checking the
    signature.
  • The Inbox and notification settings refuse API tokens, like the other
    personal settings.
  • Open live streams of an AI session or the Inbox now close within about 15
    seconds after their account is deactivated or its password changes, and a
    session stream serves only sessions in your own workspace. Before, a
    stream checked the account only when it opened.
  • Starting an AI session with no incident is now for admins only, including
    through API tokens; operators got it before. Forcing a session past its
    model's limit stays with the incident's owner and admins.
  • Viewers and viewer API tokens no longer receive credential values from SLA
    probe targets or model configurations: probe URLs and model base URLs show
    without user names, passwords, query strings or fragments, and probe
    headers, bodies and other settings are left out. Exporting the Activity log
    as CSV is now for admins and operators; Viewers still read the Activity
    page, which the dashboard now opens to them (before, it said access denied
    while the API answered). If a probe URL or model endpoint carried a token,
    rotate it.
  • Workspace settings, invite and People routes now check that the workspace
    and person named in the request are your own workspace and its members
    (404 otherwise), and OpsMender never creates a second workspace. Before,
    an admin could read and change any workspace or person by id, including
    reset links and temporary passwords; one instance runs one workspace, so
    this only mattered if a second workspace row existed.
  • Nobody can change their own role or deactivate their own account, including
    through their API tokens; another admin can. Before, the only admin could
    demote or deactivate themselves and leave nobody able to sign in as admin.
  • A password change now revokes every API token the person created: their own
    change, an admin's temporary password and a reset link. The tokens return
    401 at once and show as revoked, each with an Activity entry. Before, a
    reset account kept working through its tokens. Create new tokens after a
    password change, including for automation an admin set up.
  • Intake refuses alert bodies over 1 MiB with 413 before reading them in
    full, including bodies sent without a length; set
    OPSMENDER_INGEST_MAX_BODY_BYTES to change the limit. Before, a body of any
    size was read and stored whole in the ingest log. The token's delivery log
    keeps a short row with the size and the limit, never the body.
  • MCP server credentials are now shown to admins only. Before this change
    every signed-in account and API token, Viewers included, could read each
    saved MCP server's command, arguments, URL and environment values, and the
    last connection error, from the server list; Operators could also read the
    launch details of servers configured in the environment from Settings.
    Others now see the name, transport, state and environment variable names.
    Rotate any credential stored in an MCP server's environment values,
    arguments or URL
    , since any account could read it.

Added

  • Operators can create, see and revoke their own Operator API tokens from
    Profile. Admins still create any role from Settings and see everyone's.
  • Operators can open the Memories page. It lists global memories and their
    teams' memories, with a Team column (Global for global memories) and a team
    filter; operators edit or delete only their teams' memories.
  • Hand several incidents to another team at once from the incident list
    (Actions > Hand off to team), with one required note. Each incident keeps
    its service and gets the note on its timeline; if any can't be handed off,
    none move.
  • Operators can ask someone from another team to join an incident as a
    responder. The person gets an Inbox notice and an email naming who asked,
    and only they accept or decline from the incident page. A pending request
    holds one of the three responder slots until it is answered, expires after
    30 minutes or the incident closes, and the requester learns the outcome.

Removed

  • Memory feedback: the thumbs on the Memories page and in a session's
    Memories used panel, POST /memories/{id}/feedback, and the
    helpful_count and unhelpful_count fields of memory responses. Recall
    ranking and eviction no longer weigh old feedback; pinned memories are
    still never evicted.

Fixed

  • The API's OpenAPI document now reports the installed version (1.1.1), the
    same one opsmender --version prints; it said 0.2.0 whatever the release.
  • The models and the database migrations now describe the same schema. On
    PostgreSQL, the names of ingest tokens, MCP servers, model configurations,
    skills, SLA targets and workflow profiles are unique per workspace, as the
    models already said, and the models declare the JSONB columns and indexes
    the migrations create. Saved data doesn't change. CI now fails a change
    whose models and migrations disagree.
  • Scheduled reports keep their day and local time. A monthly report set
    for the 31st runs on the last day of shorter months and returns to the 31st
    (before, it moved to the 28th for good after February), and a weekly 09:00
    report stays at 09:00 in its time zone when the clocks change (before, it
    ran at a fixed UTC time and moved an hour). Existing schedules keep their
    next run's day and time, in UTC.
  • Identical alerts that arrive at the same moment now all get a normal
    answer and open one incident; before, all but one could fail with a server
    error on PostgreSQL. Two Takes at the same moment on an incident without
    an Escalation Chain now leave one owner and give the other the usual 409
    instead of a server error.
  • An operator's Maintenance Window now lasts at most 24 hours, tells the
    admins and the covered teams in their Inbox when it becomes active, and can
    be edited, ended early (End now) or deleted by the operator who created
    it; other operators can't, and only an admin changes what it covers. Before,
    it could last years, told nobody, and its creator couldn't end it.
  • Taking someone off a Roster no longer moves everyone else's shifts. Removing,
    deactivating or demoting a member to Viewer now keeps their place in the
    rotation, and its shifts go to the next member. Before, the rotation was
    recounted, so other people's shifts moved, the current one included.
    Demoting someone to Viewer now takes them off every Roster, as deactivation
    does (before, they stayed on it and paging skipped them), and both
    confirmations list the Rosters and who takes the current shift.
  • Deactivating someone or making them a Viewer now stops their remaining
    notification stages at once; before, their My Routing stages kept arriving
    on incidents they could no longer act on. No stage is sent to anyone who
    isn't an active admin or operator. Someone paged after an incident has an
    owner (a responder added later, or Escalate now while the owner keeps it)
    now gets only the first stage of their plan instead of every stage.
  • The next Escalation Chain level no longer pages before the people the
    current level paged have had all their own notification stages. A level
    escalates at the later of its timeout and the end of everyone's stages plus
    an answer window (the last stage's wait; none if that stage couldn't be
    sent), unless someone acknowledges. Someone with no stages saved, or who is
    no longer an active admin or operator, holds nothing: the level timeout
    alone decides. The wait for people's stages ends at most 10 minutes after
    the level paged for P0 and P1 incidents, and 20 for P2 and P3; a longer
    level timeout still applies. New levels and new My Routing stages wait 3
    minutes (new levels waited 5 before), so with three stages at the default
    wait, levels fire 9 minutes apart. My Routing shows the last stage's wait
    as the answer window and warns when a priority's stages and answer window
    take longer than that priority's limit; the chain editor's Preview timeline
    shows each level's earliest time.
  • A recovery that arrives during a Maintenance Window now closes the incident
    it clears, stopping its Escalation Chain and AI session without paging
    anyone. Before, the window dropped it with every other alert, so an incident
    opened before the window stayed open. New alerts in the window are still
    dropped.
  • Deleting an incident also deletes the incidents combined into it, including
    ones combined into those, and Activity records each with the incident it
    was combined into. The delete confirmation lists them first, on the incident
    list, in bulk and on the incident page. Before, they stayed behind with no
    incident to point to, and their alert was swallowed when it fired again: it
    now opens a new incident and pages, as do SLO violations, for incidents left
    behind by earlier deletes.
  • Saving a postmortem's memory candidates follows the memory rules: operators
    save them only for incidents on their teams' services, and an incident with
    no service (Global memories) needs an admin. The postmortem editor and guide
    no longer say saved candidates wait for review; like every memory, they are
    recallable at once. Writing the postmortem follows the Resolve rule: admins
    and operators on the team handling the incident write it, everyone else
    reads it.
  • An operator's Maintenance Window on services their teams own, or on their
    own teams, now takes effect at once instead of waiting for an admin. Other
    operator windows still wait for approval, and a window naming a service,
    team or Roster that doesn't exist is refused.
  • Updated the locked langgraph to 1.2.14, which brings langgraph-sdk 0.4.6
    with the upstream fix for an authorization bypass in its resource handler
    registration (CVE-2026-104873), along with langchain-core 1.6.7. OpsMender
    uses only langgraph's graph runtime, not the SDK's handlers.
  • Operators, including an owner from another team, add responders only from
    the team handling the incident (anyone when it has no team); admins still
    add anyone. A refusal names the person and adds nobody, and the Add
    responders dialog lists only the handling team for operators.
  • The owner and admins now control an incident's AI session: they start it,
    take it over, stop it, switch its model, override its tier and message it,
    on the web and from chat. Others watch; Start session stays disabled until
    you take the incident. Starting, taking over or overriding a session never
    changes who owns the incident. Approvals from an incident's AI session are
    answered by its owner, operators of the team handling it and admins, on the
    web and in chat.
  • Only admins and operators on the team handling an incident can resolve,
    reopen or combine it, whether or not they own it or are helping. Responders
    and owners from another team are refused on the incident page, the incident
    list, Slack /resolve, chat buttons and phone key 3, and the incident page
    shows Resolve only to people who can use it. Acknowledge no longer shows on
    an incident someone else owns; Take over asks them instead.
  • An active owner now keeps an incident at every priority. Others who try to
    acknowledge or take it are refused; assigning someone else over an owner
    needs an admin or an operator of the handling team, a member of that team
    as the new owner, and a note, which the previous owner receives in a notice.
    Bulk reassign, and bulk acknowledge for someone else, follow the same rule.
    Only the owner or an admin can release an incident, in OpsMender or with
    Slack /release. Take over on an incident without an Escalation Chain, in
    OpsMender or with Slack /take, now says to use Force take instead of doing
    nothing or asking for an admin.
  • Only the team handling an incident can take or acknowledge it. Operators
    outside that team are refused on every path (Take, Acknowledge, bulk
    acknowledge, takeover requests, Slack /ack and /take, chat buttons and
    phone key 1) unless its Escalation Chain paged them in the current run.
    Admins always can, and incidents with no team keep the any-operator rule.
    Take and Acknowledge show only for people who can use them.
  • The design audit gate (scripts/design_audit.mjs) now fails when the
    accessibility checker crashes on a page, when a page can't be captured, or
    when nothing was captured at all. Pages that need a record the environment
    doesn't have are listed as NOT RUN instead of being skipped silently. CI
    checks these rules without a browser.
  • Reliability Maintenance Windows now send an explicit scope: All Targets
    covers the workspace, a linked target covers its service, and a standalone
    target covers only that probe. Create and update reject specific target IDs
    under global scope and reject unknown or other-workspace probe IDs. Changing
    a selection clears the previous service scope. Loading targets preserves
    a new window's draft. Existing windows are not
    rewritten automatically.
  • Monolith startup now stops AI sessions interrupted by an app restart,
    records the interruption in their summaries and incident timelines, and
    expires their pending approvals. Their model slots are freed for queued
    sessions without retrying interrupted work. Queued sessions and approval
    holds remain with their existing queue and expiry rules.
  • Personal notification steps are now claimed under a database lock. Two
    schedulers can no longer send the same step twice, and an acknowledgement
    or resolution that arrives while a step is being sent waits for that send,
    then stops the rest: nothing is sent after it, and the step keeps the
    acknowledged or resolved status. A team handoff, responder removal or
    deletion during a send waits instead of failing, and steps still running on
    a closed incident now stop.
  • Permanently deleting an incident, singly or in bulk, now records an Activity
    entry for each incident (who deleted it, its title and when) in the same
    transaction, and keeps its AI sessions' earlier Activity entries instead of
    deleting them. Overlapping deletion requests cannot add duplicate entries.
    The delete confirmations say so.
  • Reassigning an incident to another team and moving it to another service
    now require a note. A missing or blank note is refused and nothing moves;
    the note appears on the incident timeline. The Reassign and Manage incident
    dialogs mark the note as required.
  • Chat actions and role-based notices now use the role shown on People, the
    same role as sign-in and phone keys. A viewer demoted there can no longer
    act from chat, an operator promoted there can, and new-incident, approval
    and other role-targeted notices follow People role changes.
  • Viewers are no longer paged or made incident owners. Team levels page only
    their admins and operators; a user or roster level whose person is now a
    viewer on People is skipped as empty; adding an escalation level for a viewer
    or assigning an incident to one is refused.
  • Phone keypad actions now check the caller's access when the key is pressed:
    an active account, workspace membership and the Admin or Operator role shown
    on People. Viewers, removed members and disabled or deleted users can no
    longer acknowledge, escalate or resolve an incident through an unexpired
    phone link.
  • Darkened the green, amber and cyan initials-avatar backgrounds so their white
    text meets the minimum contrast ratio without changing saved color choices.
  • Voice Call stages now reach the configured calling channel and use the same
    spoken summary and signed keypad link as immediate phone pages. Missing
    configuration or a phone number records a skipped attempt with its reason;
    answering a call does not acknowledge the incident.
  • Approved active Maintenance Windows now cover uptime samples by global,
    service or team scope as well as legacy target lists. Roster windows do not
    cover samples. Matching windows prevent new SLO burn incidents, including
    burns from earlier outages; checks resume normally when the window ends.
  • Raised the PyJWT minimum to 2.14 and refreshed the locked package to include
    upstream fixes for token verification and key handling vulnerabilities.
  • Updated the locked urllib3 to 2.8.0 for upstream fixes to HTTPS proxy TLS
    settings and unbounded memory use in chunked responses.
  • An API token now acts at the lower of its own role and its creator's current
    role in every permission check. Previously some incident, team, responder,
    comment, maintenance and memory checks read the creator's account role, so an
    Operator token created by an Admin could delete incidents, force-take or
    reassign another team's incidents, delete other people's comments and
    self-approve global Maintenance Windows. Demoting a token's creator now
    lowers the token too.
  • Operators can no longer create global memories; global memories need an
    Admin, as editing and deleting them already did.
  • Skill Studio now saves a reviewed policy change when Save is clicked from
    the content editor. Debounced validation and validation on save remain active.
  • Demo seeding no longer prints its database connection URL. Demo users and
    invitations use reserved example addresses.
  • The local image scanner reads the existing unfixed-vulnerability policy
    from the correct configuration key, matching the hosted scan.

Changed

  • Uptime and SLO percentages count maintenance samples as up instead of
    excluding them. Two up, one down and two maintenance samples now report 80%
    uptime, with one minute of downtime and two minutes of maintenance. Probe
    results remain available in Outage History. Reliability now describes covered
    samples as up, matching these numbers.
  • Refreshed all 13 demo screenshots from one clean seed, including the Tier 1
    approval view. The capture script checks for test debris and real email
    addresses. Browser QA now verifies policy widening, advisory-only services,
    and overlapping tool sources with a single-source control.

Added

  • Reassign to another team. An incident that reached the wrong team can be
    handed to the team it belongs to from the incident page. Admins and
    operators on the incident's team can reassign it. The owner is released, the
    receiving team's Escalation Chain pages from the first level (P2 and P3
    incidents notify its members in their Inbox instead), and the timeline
    records who moved it, where, and the optional note. The incident keeps its
    service; the new team handles force takes, filters, reports, team-scoped
    channel updates, and paging after a reopen.

  • Add responders. Up to three people can be asked to help with an
    incident besides its owner. Each one is paged once through their own
    notification settings (Maintenance Windows don't hold the request) and gets
    an Inbox notice with the optional message. Responders show next to the
    owner, can be removed, and can leave.

  • Workspace change history. Authenticated configuration changes now write
    Activity entries with the actor, route, entity, operation, and a short
    redacted before/after summary. Approval decisions name the decider, and
    session tier overrides record the actor and tier transition. Credential
    values are not copied into Activity. A change and its entry are saved in
    the same database transaction, so if the entry cannot be written the change
    is rolled back and the request fails. A row changed in several steps, such
    as a reorder, gets one entry, and rows whose values did not change get none.

  • Reopen pages again. Reopening a resolved P0 or P1 incident starts a new
    escalation round at the first level and releases its former owner. The
    timeline says whether paging restarted or why nobody was paged.

  • Takeover consent in the incident page. Take on another person's incident
    asks its owner to hand it over; the owner receives an Inbox notice and can
    confirm within five minutes. The request then expires without changing
    ownership. An admin, or an operator on the current owner's service team,
    can force a takeover immediately with a required reason; the former owner
    is notified and the reason appears on the timeline.

  • Cross-service alert collision notice. When a provider-scoped alert is
    absorbed by another service's active incident, the receiving service's
    Escalation Chain responders get one Inbox notice (their Inbox mute
    applies), and Respond channels scoped to the receiving team get one
    informational message. The ingest log and the incident timeline record
    both services. The incident's owner doesn't change, and nobody on the
    receiving service is paged.

  • Tool-source overlap warning. When a Service allowlists an MCP server and
    a native connector that appear to reach the same system (an Atlassian MCP
    server and a Jira connector, say), the Services table marks it
    Overlapping tool sources, the service editor explains why, and
    opsmender doctor reports a warning. Both tool sets still reach the AI,
    which picks by description, and only the native connector links tickets to
    the incident. The check is a heuristic and advisory only: it never changes
    which tools a session gets and never blocks a session. Overlap details are
    shown to admins and operators only.

Changed

  • Escalation Chain ties now prefer the earliest service link. Links that
    existed before this upgrade share a backfilled creation time and retain
    their former UUID tie order. The collision notice uses the same active-chain
    selection as paging.

  • MTTR now uses the incident's resolution timestamp, so later edits do not
    move the metric. Existing resolved incidents are backfilled from their last
    update time, the only timestamp available before this upgrade.

  • The populated-data escalation migration archives extra duplicate page
    markers as recorded_legacy and advances affected chains to round 1.
    Their next handoff therefore starts round 2; unaffected chains remain at
    round 0.

  • Handoff actions recheck permission after locking. If another operator
    moves the incident to a new team before a reassignment or responder change
    completes, the earlier team's operator cannot finish the stale action.

  • Plain punctuation in tier gate messages. Blocked and approval reasons
    from the tier gate now use a colon or comma instead of a dash, for example
    "deny-list policy match: blocked at every tier". Only the wording changed;
    the gate's decisions are identical. The punctuation check now covers the
    tier gate too.

  • One MCP server per service. The service editor selects one server; the
    API rejects several with 422. Existing services that list several show a
    warning, and saving keeps the selected one.

  • P0 and P1 page; P2 and P3 notify. P3 incidents now notify, like P2,
    instead of getting the unused "auto resolve" mode. New services default to
    P1, and the service form explains which priorities page. Existing
    services keep their priority: a service still at the old default, P2,
    won't page until you raise it.

  • Low-severity alerts notify. An alert whose severity is low or info
    notifies instead of paging, even on a P0 or P1 service; the incident keeps
    the service's priority and its timeline says why it didn't page. The
    generic intake adapter now reads info and informational as low
    (it used to read them as medium).

  • Plain punctuation throughout. The app, its messages, the docs and the
    CLI no longer use em or en dashes. The browser tab reads "OpsMender";
    empty values show a word ("None", "Never", "No data") instead of a dash;
    tier options read "Tier 0: Autonomous"; and CloudWatch, GCP, OCI and
    BugSnag alert titles use a colon ("[CloudWatch] cpu-high: ALARM"). New
    Skills from the template use "## Tier 0: Autonomous" headings; Skills
    with the older headings still parse. The AI is asked to write plainly
    and skip em dashes, too. Incidents already stored keep their titles.

  • Sessions without a service get no integrations. A service's allowlist is
    what grants integration tools, so an incident with no service (a manual P2
    or P3, or an SLO with no service) no longer gets every enabled connector.

  • Helm sets FORWARDED_ALLOW_IPS when ingress is enabled, from the new
    ingress.trustedProxies value (default "*"). Behind an ingress every
    request comes from the ingress controller, so without it sign-in limits
    counted everyone as one address and five wrong passwords locked an account
    for everyone. Narrow it to your ingress controller's pod CIDR if other
    workloads in the cluster aren't trusted.

Fixed

  • Incident-created Inbox notices exclude deactivated and deleted users.

  • /ack in chat names the current owner and suggests /take when someone
    else holds the incident lock.

  • Shared dialogs announce their title to assistive technology and keep
    keyboard focus inside until closed.

  • The quiet-hours regression test uses a fixed UTC time instead of depending
    on the minute the suite happens to run.

  • Paging the same person again. When someone whose staged notifications
    had finished is paged again for the same incident (a new round, a reopen, or
    a responder request), their notifications start over instead of being
    skipped.

  • Service handoff notes. Moving an incident to another service now records
    the move and the optional handoff note on the timeline; the note was
    previously dropped.

  • Long incident titles in the Inbox. Inbox notices shorten titles to fit,
    and a failed notice no longer fails the action that sent it.

  • One combined alert clearing no longer resolves the incident. When
    alerts were combined, a recovery for one of them resolved the whole
    incident and stopped paging. The incident now stays open, notes the
    cleared alert on its timeline, and resolves when its own alert clears.

  • Escalate now on an owned incident pages one level. It used to turn the
    owner's lock back into running escalation, so later levels kept paging on
    schedule while someone owned the incident. The owner now keeps the lock.

  • Deleting an ingest token that has received alerts returns 409 and
    asks you to revoke it instead; it used to fail with a server error on
    Postgres. Its delivery log is kept as an audit record.

  • Connector Skill instructions reach the AI. A Skill bound to an
    integration connector could restrict the connector's tools, but its written
    Custom Instructions never reached the model; for a service with only
    integrations, the AI got no instructions at all. A session now receives the
    active tier's instructions from each allowlisted connector's Skill, after
    the MCP Skill's and labelled with the connector, at every stage. They are
    guidance only and can't lift an approval or a deny. Connector AI Action
    Workflows are still not used; sessions follow the MCP Skill's workflow.

  • SLO burn-rate incidents page. They take their service's priority and
    page its Escalation Chain like any other incident; before, they never
    paged. A violation after the previous one resolved opens a new incident
    instead of reopening the old one. Manual incidents, intake and SLO
    violations now start paging through one shared path.

  • Recurring Maintenance Windows recur. A window with a recurrence rule
    (for example FREQ=WEEKLY;BYDAY=SU) now covers every repeat, not just the
    first. An unreadable rule, or one repeating more often than hourly, is
    rejected with 422. Team-scoped windows now also hold back pages, not just
    intake, and Roster-scoped windows hold back pages sent through that
    Roster's escalation level; before, they did nothing.
    Upgrade note: existing recurring windows start repeating after the
    upgrade. Check them before upgrading if any were set up long ago.

  • The Reliability page no longer promises a P0. Creating an incident
    from an SLO recommendation said it would be P0 and page; it takes the
    service's priority.

  • Everyone agrees on who is on call. Paging, the on-call API, the Roster
    and chain calendars, and the Services table now build the on-call picture
    the same way, from the Roster's real coverage window. Before, paging used a
    default 09:00-17:00 window, so a night Roster could page nobody at 03:00
    while the calendar named someone.

    • Shifts hand over at the Roster's handoff time (its coverage start), on the
      Start Date and every shift after it. A round-the-clock Roster used to
      switch people at local midnight. The weekly handoff day is the Start
      Date's weekday; the unused handoff_day field stays legacy.
    • The Services table's "On call now" resolves at the current time instead
      of the middle of today's coverage window. The chain calendar API accepts
      at (with range=today) for this.
    • The Dashboard's on-call coverage and the Rosters page's "On call now"
      are right for Rosters in any time zone. Asked for "now", the on-call API
      used the server's clock without a zone and read it as Roster-local time,
      so a New York Roster at 13:00 showed nobody on a UTC server.
    • An Override for a deactivated user is ignored everywhere, as paging
      already did, and is no longer flagged on the Roster calendar.
  • Quiet hours never block a page to the on-call person (D-4). When a
    level targets a Roster, the person on call is paged even inside their quiet
    hours. Quiet hours still apply to direct and team targets, and any page held
    back by quiet hours or a Maintenance Window is now recorded as a skipped
    delivery with the reason and a timeline note. Before, it vanished without a
    record.

  • Notification preferences are validated. Malformed quiet hours or routing
    return 422 instead of failing silently at page time. Saving paging routing
    no longer wipes the Inbox mutes set on the Inbox preferences page.
    Upgrade note: an older nested quiet-hours shape ({"weekday": {...}})
    was never read by paging and is now rejected on save; stored values load
    unchanged.

  • Escalation chains now visit every eligible level once. The first level
    no longer stops at a 15-minute start-time cap. Each level, including the
    final one, keeps its configured timeout; an unacknowledged chain then sends
    one exhaustion notice to the team's Notification Channels and responders'
    Inbox. An inactivity lock that lapses with no next level sends the same
    notice while leaving the owner assigned.

  • Deleting a level compacts the chain without skipping the next level in an
    active incident. Empty or inactive targets are skipped immediately; a
    suppressed or unconfigured delivery keeps its level timeout. A service
    selects a matching priority chain, then an unfiltered chain, and warns on
    the incident timeline and service form when none matches.

  • Logical page markers now carry a run round and are unique per incident,
    responder, level and round. Later levels and service handoffs can page the
    same responder again without colliding with prior delivery history. Roster
    writes reject invalid time zones and times, and an explicit null in a
    Roster update leaves that field unchanged instead of failing.
    Upgrade note: duplicate historical logical markers are retained as
    recorded_legacy; physical delivery and acknowledgement records are kept.
    The nullable hard_deadline_at column remains for compatibility but is no
    longer used. Database claims prevent overlapping workers from dispatching
    the same level twice; acceptance by a remote channel cannot be guaranteed
    exactly once across a crash or ambiguous network response.

  • Owning or closing an incident now stops paging, everywhere.

    • Resolving through the web page, the incident list, phone keypad 3, an
      alert recovery, a chat button, Slack /resolve, or combining incidents
      stops the Escalation Chain and staged notifications, including snoozed
      and acknowledged chains. Before, only chat and Slack resolves did.
    • Every way of taking ownership acknowledges the incident and stops paging:
      Take, bulk acknowledge and reassign, phone keypad 1, chat
      Acknowledge, and taking over an AI session.
    • Acknowledging holds the incident under a lock (D-021). The owner's own
      recorded actions keep it; 15 minutes without any of them, or a release,
      pages the next level (never level 1 again).
    • Slack /snooze resumes the next level when the snooze ends (it used to
      stay paused forever), and extends an owner's lock instead of dropping it.
      Escalate now also works on snoozed and acknowledged chains. A snooze can last
      up to seven days.
    • Only the current owner can confirm a takeover request (an admin can still
      force one), and an unanswered request expires without a transfer.
    • Changing the service of a resolved incident no longer restarts paging.
    • Phone keypad 1 checks the current owner, so a responder paged after a
      release can take the incident.
    • Inbox links for assignments, mentions and combined incidents open the
      incident page instead of a missing page.
  • API. POST /incidents/{id}/ack, /assign, /take and the bulk
    acknowledge/reassign actions return 409 for a resolved or merged incident.
    /ack returns 409 while someone else holds the lock (use Take over or a
    takeover request). Assigning an inactive user, or one outside the
    workspace, returns 422. Confirming someone else's takeover returns 403, and
    an expired request 409. The chain panel adds paused_until and
    last_activity_at.
    Upgrade note: chains acknowledged before the upgrade stay finished, and
    Slack snoozes set before it stay paused; neither re-pages on upgrade.

  • SNS-wrapped CloudWatch alarms sent to a service intake URL now use the inner
    alarm identity and state, so they dedup, and an OK resolves the incident.
    Plain-text SNS messages still open an incident titled from the Subject or
    message. Clearing alerts resolve only live incidents, and a firing alert
    after resolution opens a new incident whether or not alert grouping is on.
    A recovery with no live incident is logged and skipped instead of creating
    a resolved incident that pages. Ingested firing and acknowledgment states
    map to open (the undefined investigating status is gone). A service
    intake URL always uses its own token, even when other tokens are bound to
    the service. JSON nested more than 64 levels deep is rejected with a 422.
    Upgrade note: if a service's intake URL previously resolved to another
    token bound to the same service, incidents it opened before the upgrade
    won't match later deliveries; resolve those by hand.

Security

  • Accepted SAML assertion IDs are claimed in the database for their validity
    window, so a replay is rejected across app workers. Assertions without an ID
    or expiry are rejected. The container vulnerability scan now runs on pull
    requests as well as on main.

  • Intake URLs are stored as a hash and shown once. A service's intake URL
    carries the secret that lets a monitor post alerts and page a team, and it
    used to be stored as plain text. Now only a hash is kept; the full URL is
    shown once, when the service is created or an admin rotates it (Rotate
    URL
    , POST /services/{id}/intake-url). Existing URLs keep working.
    GET /services returns a masked intake_url_hint to admins and operators
    instead of intake_url. The access log shows only the first eight
    characters of the secret, and revoking the URL's ingest token now retires
    the URL instead of failing or quietly re-enabling it.

  • A password change or reset ends older sessions. Tokens issued before an
    admin reset, a reset link or a self-service change stop working on the API,
    the live streams and a pending MFA challenge. POST /auth/me/password now
    returns a fresh token (200) instead of 204, so whoever changed their own
    password stays signed in. The live streams also refuse a deactivated
    user's token.

  • A deny rule wins wherever it appears in a Skill. A deny: true entry
    written below a broad glob such as * was ignored, so the denied tool ran
    autonomously at Tier 0 and Tier 1; connector Skills had the same gap. Deny
    now wins in any order, and over an exact entry for a tool a deny glob
    matches, so narrow the glob to allow one tool. allow_generic opts a
    generic runner out of the guardrail only on an exact-name entry, not a
    glob.

  • Chat approvals follow the same rules as the web. /approve and
    /reject from chat refused nothing after the request expired and recorded
    no approver; they now expire like the web, record the linked OpsMender
    user, and count as the owner's activity. Chat commands also require a
    verified user link.

  • Viewers no longer see intake URLs. The URL carries the secret that
    lets a monitor post alerts and page the team; only admins and operators
    get it.

  • Failed sign-ins are limited. Login, MFA verification, registration,
    password-reset and invite links, and the SSO and SAML callbacks now refuse
    a caller with 429 and Retry-After after repeated failures: 5 per account
    from one address and 100 per address in 15 minutes (configurable; 0
    turns a limit off). Reaching a limit writes one sign_in_lockout audit
    entry. Keying on the address as well as the account means nobody can lock
    another user out just by knowing their username.
    Upgrade note: behind a reverse proxy, set FORWARDED_ALLOW_IPS to the
    proxy's address, or every user shares the proxy's address and its limits.

  • A deleted service's intake URL stops working. Deleting a service now
    revokes its ingest tokens; before, the old URL kept creating incidents
    with no service.

  • Upgraded anyio from 4.13.0 to 4.14.2 (4.15.1 on Python 3.15+) to fix
    CVE-2026-63374 (critical). anyio is a transitive dependency of httpx,
    FastAPI, and the model SDKs; no application code changed.

Documentation

  • The integrations guide explains how to keep one source per capability
    (including the connector-skill deny that keeps only the MCP route), that a
    connector's project_key is a default rather than a limit, and why
    connector names should carry the project or space key.
  • The paging guide documents the full phone keypad (1 acknowledge, 2
    escalate, 3 resolve, * repeat), that the menu needs
    OPSMENDER_PUBLIC_URL, and that the voice status-callback URL has no
    receiving route in OpsMender (the .env.example said otherwise).
  • The notification-preferences guide now matches the product: only P0 and P1
    page, so the P2 and P3 routing rows aren't used; quiet hours can only hold
    back P1; a chat stage posts to the channel's shared chat, not a direct
    message; "sent" means the provider accepted a delivery, with no retries or
    fallback; and Maintenance Windows cover team and Roster scopes and can
    repeat. The Slack guide notes /snooze defaults to 30m.
  • My Routing says which priorities page: P2 and P3 are marked "Doesn't
    page, so these stages aren't used".