1import{$ as C,D as u,O as s,S as t,T as d,Y as c,Z as v,ct as h,g as _,j as A,jt as o,k as i,vt as I}from"./charts-CoMztkZX.js";import{l as T}from"./vue-vendor-DCDA2qdC.js";import{_t as q,ht as m}from"./vuetify-CMosaK0X.js";import{U as R}from"./index-CladleKL.js";import{t as S}from"./ga4-client-tYg4HZ25.js";import{c as W,t as E}from"./SiteFooter-Bw_pcZr4.js";var N={class:"article-page"},V={class:"hero"},D={class:"hero__inner"},L={class:"hero__cmd"},J=["aria-label"],$={class:"hero__actions"},B={class:"shipped"},M={class:"section-container"},O={class:"shipped__grid"},P={class:"shipped__icon"},z={class:"shipped__title"},F={class:"shipped__body"},G={class:"shipped__aside"},H={class:"decisions"},U={class:"section-container"},X={class:"decisions__grid"},Y={class:"decisions__title"},Z={class:"decisions__body"},K={class:"rollout"},Q={class:"section-container"},ee={class:"rollout__grid"},te={class:"rollout__num"},ae={class:"rollout__title"},se={class:"rollout__body"},ie={class:"cta"},oe={class:"section-container cta__inner"},ne={class:"cta__actions"},re=A({__name:"release-jails",setup(le){const{global:f}=q();f.current.value.dark&&(f.name.value="light");const p=S(),y=T(),n=I(!1),b=()=>{navigator.clipboard.writeText("vulnetix jail"),n.value=!0,setTimeout(()=>{n.value=!1},2e3),p.trackInteraction("cli_command_copied","engagement","article_jails_launch")},w=()=>{p.trackInteraction("demo_dialog_opened","engagement","article_jails_launch"),y.push("/request-a-demo")},r=g=>{p.trackInteraction("cross_link_click","navigation",g)},k=[{icon:"mdi-console-line",title:"vulnetix jail",body:"Assesses the repository against your organisation policy and sets the exit code. Subcommands explain, list and exempt inspect and waive without gating."},{icon:"mdi-view-dashboard-outline",title:"A policy editor in the console",body:"Ordered rules under Configuration, alongside the quality gate. Rules are read at run time, so a change applies on the next pipeline run rather than the next release."},{icon:"mdi-file-certificate-outline",title:"Attestations on every run",body:"OpenVEX or CycloneDX for the vulnerability breaches, SARIF for end-of-life, goals and hygiene. Written before the exit code is decided, so a failing run still leaves evidence."},{icon:"mdi-flag-outline",title:"A --jail flag on every scan command",body:"Upload and assess in one invocation. The categories that run refresh their own evidence; everything else is still graded on what it has."}],x=[{title:"A breach beats an unknown",body:"When one rule breaches and another cannot be evaluated, the run exits 1, not 3. A violation we can prove is more actionable than an absence, and reporting the absence first would send the reader to inspect a pipeline while a known exploited vulnerability sat in the backlog."},{title:"Missing evidence is not a pass",body:"The default for stale or absent coverage is to refuse a verdict. It would have been easier to grade whatever was there, and the result would be a gate that reports a repository as clean on the strength of a scan that stopped running months ago."},{title:"Commit drift never gates",body:"We built it to gate on commit equality first and reverted that. A pull request build scans the merge commit while the gate runs on the head commit, so the strict version jailed every pull request on the first day. It is reported to the reader and left out of the decision."},{title:"A goal warns before it blocks",body:"A migration rule that fails the build the moment it is written is a threshold with a date attached, and teams route around those. Goals report until their deadline. The ratchet is the separate, smaller promise: the count is not allowed to rise while the clock runs."},{title:"Exemptions expire",body:"There is no permanent waiver. A waiver that never ends is a policy change, and it belongs in the policy where somebody can see it rather than in an exception list nobody reads."},{title:"The frozen cohort was left alone",body:"Campaign membership stays keyed on the identity that survives a rescan. Binding it to a foreign key would have been tidier and would have broken every cohort whose repository row was later re-minted."}],j=[{step:"1",title:"Add the command",body:'An organisation with no policy reports "no policy" and exits 0. Nothing changes until a rule exists.'},{step:"2",title:"Write one rule",body:"Most teams can name their first from memory. Start with the remediation window you already publish."},{step:"3",title:"Watch it for a sprint",body:"Run with --no-fail. The full verdict is reported and the exit code stays 0."},{step:"4",title:"Enforce",body:"Remove the flag. If it goes badly, set enforcement to warn in the console and every rule downgrades at once, without a CLI release."}];return(g,e)=>{const l=C("RouterLink");return c(),d("div",N,[i(W),t("section",V,[t("div",D,[e[6]||(e[6]=u('<span class="hero__eyebrow" data-v-4e9f4929>Product Announcement · 21 August 2026</span><h1 class="hero__title" data-v-4e9f4929> Release Jails are live.<br data-v-4e9f4929><span class="hero__title-accent" data-v-4e9f4929>Gate a pipeline on the repository, not just the build.</span></h1><p class="hero__subtitle" data-v-4e9f4929> A scan answers one question: what is in this code right now. It cannot answer the question a security programme actually runs on, which is whether the backlog is getting worked. Jails put that question in the pipeline. A repository is jailed when it breaches a policy your organisation set, measured across every tool and category that has ever reported for it. </p><div class="hero__stats" data-v-4e9f4929><div class="hero__stat" data-v-4e9f4929><span class="hero__stat-value" data-v-4e9f4929>4</span><span class="hero__stat-label" data-v-4e9f4929>Rule kinds, one shape</span></div><div class="hero__stat-divider" data-v-4e9f4929></div><div class="hero__stat" data-v-4e9f4929><span class="hero__stat-value" data-v-4e9f4929>3</span><span class="hero__stat-label" data-v-4e9f4929>Exit code for evidence we could not reach</span></div><div class="hero__stat-divider" data-v-4e9f4929></div><div class="hero__stat" data-v-4e9f4929><span class="hero__stat-value" data-v-4e9f4929>0</span><span class="hero__stat-label" data-v-4e9f4929>Pipelines broken before your first rule</span></div></div>
1',4)),t("div",L,[e[4]||(e[4]=t("code",null,"vulnetix jail",-1)),t("button",{class:"hero__copy",type:"button","aria-label":n.value?"Command copied":"Copy command",onClick:b},[i(m,{icon:n.value?"mdi-check":"mdi-content-copy",size:"17"},null,8,["icon"])],8,J)]),t("div",$,[i(l,{to:"/features/jails",class:"hero__btn-primary",onClick:e[0]||(e[0]=a=>r("article_jails_feature"))},{default:h(()=>[...e[5]||(e[5]=[s(" See the use cases ",-1)])]),_:1}),t("button",{class:"hero__btn-text",onClick:w}," Request a demo ")])])]),e[23]||(e[23]=u('<section class="gap" data-v-4e9f4929><div class="section-container" data-v-4e9f4929><p class="section-label" data-v-4e9f4929> Why we built it </p><h2 class="section-heading" data-v-4e9f4929> The gap this closes. </h2><p class="prose" data-v-4e9f4929> We already ship a quality gate. It grades one scan and decides whether the findings that run produced should fail that build. It is good at what it does and it has a blind spot: a repository can pass every individual scan for a year while its backlog grows, its runtimes go out of support, and the migration everyone agreed to in January stays exactly where it was. </p><p class="prose" data-v-4e9f4929> Nothing in a per-scan gate can see that, because none of it is visible in a single run. It is visible in the accumulation, which is where the policies organisations actually write live. Seven days for a critical. No end-of-life runtimes in production. Off the deprecated HTTP client by the end of the quarter. Those are policies, and until now the only thing enforcing them was somebody remembering to check. </p><p class="prose" data-v-4e9f4929> Release Jails are the enforcement. Same command shape as everything else in the CLI, one exit code, and the policy lives in the console where it can be reviewed. </p></div></section>',1)),t("section",B,[t("div",M,[e[10]||(e[10]=t("p",{class:"section-label section-label--dark"}," In this release ",-1)),e[11]||(e[11]=t("h2",{class:"section-heading section-heading--dark"}," What shipped. ",-1)),t("div",O,[(c(),d(_,null,v(k,a=>t("article",{key:a.title,class:"shipped__card"},[t("div",P,[i(m,{icon:a.icon,size:"23"},null,8,["icon"])]),t("h3",z,o(a.title),1),t("p",F,o(a.body),1)])),64))]),t("p",G,[e[8]||(e[8]=s(" Rules come in four kinds: vulnerabilities, end-of-life, strategic goals and hygiene. They share one shape, so learning one teaches you the rest. The ",-1)),i(l,{to:"/features/jails",class:"inline-link",onClick:e[1]||(e[1]=a=>r("article_jails_feature_inline"))},{default:h(()=>[...e[7]||(e[7]=[s("feature page",-1)])]),_:1}),e[9]||(e[9]=s(" walks through what each is for. ",-1))])])]),e[24]||(e[24]=u('<section class="exit3" data-v-4e9f4929><div class="section-container exit3__inner" data-v-4e9f4929><div class="exit3__mark" data-v-4e9f4929><span class="exit3__num" data-v-4e9f4929>3</span><span class="exit3__caption" data-v-4e9f4929>exit code</span></div><div class="exit3__copy" data-v-4e9f4929><p class="section-label section-label--dark" data-v-4e9f4929> The part we care most about </p><h2 class="section-heading section-heading--dark" data-v-4e9f4929> A gate needs somewhere to say "I could not tell". </h2><p class="prose prose--dark" data-v-4e9f4929> Most gates have two outcomes. Passed, or did not. We added a third for the case where the gate ran and could not reach a verdict, because the evidence a rule needs is stale or was never collected. </p><p class="prose prose--dark" data-v-4e9f4929> That case is common and it is dangerous. A pipeline stage that quietly stopped running produces a repository with no recent findings, which on every dashboard in the industry looks exactly like a repository with no problems. Reporting it as a pass is the worst available answer. Reporting it as a failure is not much better, because it sends a developer hunting for a vulnerability that does not exist. </p><p class="prose prose--dark" data-v-4e9f4929> So it gets its own code. Exit 1 means a developer changes a dependency. Exit 3 means whoever owns the pipeline configuration has something to fix. The two failures have different owners, and a gate that cannot tell them apart sends half of them to the wrong person. </p></div></div></section>',1)),t("section",H,[t("div",U,[e[12]||(e[12]=t("p",{class:"section-label"}," Design notes ",-1)),e[13]||(e[13]=t("h2",{class:"section-heading"}," Decisions worth explaining. ",-1)),e[14]||(e[14]=t("p",{class:"decisions__lede"}," Several of these came from getting it wrong first. ",-1)),t("div",X,[(c(),d(_,null,v(x,a=>t("article",{key:a.title,class:"decisions__card"},[t("h3",Y,o(a.title),1),t("p",Z,o(a.body),1)])),64))])])]),t("section",K,[t("div",Q,[e[15]||(e[15]=t("p",{class:"section-label section-label--dark"}," Rollout ",-1)),e[16]||(e[16]=t("h2",{class:"section-heading section-heading--dark"}," Adopting it without breaking a pipeline. ",-1)),t("div",ee,[(c(),d(_,null,v(j,a=>t("div",{key:a.step,class:"rollout__step"},[t("div",te,o(a.step),1),t("h3",ae,o(a.title),1),t("p",se,o(a.body),1)])),64))]),e[17]||(e[17]=t("p",{class:"rollout__bridge"},[s(" Existing quality gate configuration is untouched: the two are separate policies answering separate questions, and they stay that way. "),t("em",null,[s("If you already run "),t("
1code",null,"vulnetix scan"),s(" in CI, adding "),t("code",null,"vulnetix jail"),s(" after it is the whole integration.")])],-1))])]),t("section",ie,[t("div",oe,[e[20]||(e[20]=t("p",{class:"section-label"}," Available now ",-1)),e[21]||(e[21]=t("h2",{class:"section-heading cta__heading"}," Write the policy you already have. ",-1)),e[22]||(e[22]=t("p",{class:"cta__sub"}," Release Jails are available now in the Vulnetix CLI and the console. Most teams can name their first three rules out loud. Configuring them takes about as long. ",-1)),t("div",ne,[i(l,{to:"/resolve/jail",class:"cta__btn-primary",onClick:e[2]||(e[2]=a=>r("article_jails_configure"))},{default:h(()=>[...e[18]||(e[18]=[s(" Configure a policy ",-1)])]),_:1}),i(l,{to:"/features/jails",class:"cta__btn-secondary",onClick:e[3]||(e[3]=a=>r("article_jails_feature_cta"))},{default:h(()=>[...e[19]||(e[19]=[s(" See the use cases ",-1)])]),_:1})])])]),i(E)])}}}),_e=R(re,[["__scopeId","data-v-4e9f4929"]]);export{_e as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.