@skyramp/testbot-core 0.13.0-v3.60 → 0.13.0-v3.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VERSION.json +1 -1
- package/dist/main.js +307 -307
- package/dist/post.js +2 -2
- package/package.json +1 -1
package/dist/post.js
CHANGED
|
@@ -212,7 +212,7 @@ ${o?Et().abandonedBody:Et().cancelledBody}
|
|
|
212
212
|
${s.join(`
|
|
213
213
|
`)}
|
|
214
214
|
|
|
215
|
-
<sub>[${Et().workflowRunLinkLabel}](${e})</sub>`}_T();_T();_T();Of();function Fz(t,e){if(process.env.GITHUB_ACTIONS)return new Jg(t,Pye,e);throw new Error("Unrecognized CI environment. Set GITHUB_ACTIONS=true for GitHub Actions, or use EvalPlatform directly for eval/testing.")}dt();var Gw=(r=>(r.Sufficient="sufficient",r.Insufficient="insufficient",r))(Gw||{}),qw=(d=>(d.RelatedChangeConflict="related_change_conflict",d.ReferenceOutsideTarget="reference_outside_target",d.SourceAccessLost="source_access_lost",d.ConfigurationIncomplete="configuration_incomplete",d.CredentialUnavailable="credential_unavailable",d.WorkflowBindingUnverified="workflow_binding_unverified",d.WorkflowRefUnprotected="workflow_ref_unprotected",d.DeploymentReview="deployment_review",d.SutRevisionMismatch="sut_revision_mismatch",d.IsolationUnavailable="isolation_unavailable",d.EvidenceInsufficient="evidence_insufficient",d))(qw||{}),fd=(s=>(s.CiCheck="ci_check",s.TestReport="test_report",s.StaticAnalysis="static_analysis",s.CodeReview="code_review",s.Other="other",s))(fd||{}),QT=(n=>(n.Application="application",n.Environment="environment",n.TestDefect="test_defect",n))(QT||{}),PT=(a=>(a.AuthToken="auth_token",a.Secret="secret",a.DataConnection="data_connection",a.AppNotStarted="app_not_started",a.Login="login",a.ExternalDependency="external_dependency",a.RecordingReplay="recording_replay",a))(PT||{});var DT=(n=>(n.Seed="seed",n.RuntimeMock="runtime_mock",n.EnvOverride="env_override",n))(DT||{}),OT=(n=>(n.TestCode="test_code",n.SkyrampMocker="skyramp_mocker",n.RecipeOverride="recipe_override",n))(OT||{});var Kg=(r=>(r.Ready="ready",r.Blocked="blocked",r))(Kg||{}),Dn=y.string().trim().min(1),Hst=y.object({action:y.enum(["start","run","wait"]),text:Dn,source:y.enum(["file","notes","testbot"]).describe("file: a file in the repository; notes: the Target's notes; testbot: Testbot's own finding"),file:Dn.nullable().describe("the file the step came from, relative to the component's repository; null unless source is file")}).strict().refine(t=>t.source==="file"==(t.file!==null),{path:["file"],message:"a file exactly when the step came from one"}),zst=/^[A-Za-z_][A-Za-z0-9_]*$/,Lz=/^(?!GITHUB_)(?!SKYRAMP_RUNNER_)[A-Z][A-Z0-9_]{0,99}$/,Uz={steps:y.array(Hst).max(20).optional().describe("how it starts, in order"),kind:y.enum(["web_app","service","database","external_service"]).optional(),from:y.object({file:Dn,service:Dn.nullable()}).strict().optional(),credentials:y.array(y.string().max(100).regex(zst)).max(50).optional().describe("the Target's credentials this component's recipe uses: a sign-in (a test user, password or token) or an API key, which the workflow supplies from a GitHub Actions secret as the environment variable of the credential's name; give each name exactly as the recipe reads it. Names only, never a value, and not a secret the recipe generates itself")},jst=y.object({name:Dn,repository:Dn.describe("owner/repo of the repository the component is built from"),healthy:y.boolean(),...Uz}),Vst=y.object({component:Dn,problem:Dn,evidence:Dn.describe("the exact command and output that shows it"),fix:Dn.describe("what the user must provide, and where")}),Wst=y.object({framework:Dn,file:Dn.describe("the test file run, relative to its repository root"),result:y.enum(["pass","fail","error"])}),Yst=y.object({input:Dn.describe("the part of the user's SUT input, as given"),reason:Dn}),$w=y.object({schemaVersion:y.literal(1),status:y.nativeEnum(Kg).describe("ready only if every component came up healthy and the recipe is written"),components:y.array(jst),suites:y.array(Wst).default([]).describe("one run per test suite the Target's repositories have; empty when they have none"),inputsUsed:y.array(Dn).default([]).describe("the parts of the user's SUT input the recipe used"),inputsUsedHow:y.array(y.object({input:Dn.describe("exactly as written in inputsUsed; an entry that is not there is left out"),how:Dn.describe("what the recipe did with it")})).optional(),inputsNotUsed:y.array(Yst).default([]).describe("the parts it did not use, and why"),blockers:y.array(Vst).describe("required (non-empty) when status is blocked")});function Gz(t){if(t.status==="blocked"&&!(Array.isArray(t.blockers)&&t.blockers.length>0))return['status "blocked" requires at least one blocker { component, problem, evidence, fix } \u2014 say what stopped the bring-up'];if(t.status==="ready"){let e=Array.isArray(t.components)?t.components:[];if(e.length===0)return['status "ready" requires at least one component \u2014 name each component the recipe brought up healthy'];let r=e.filter(n=>n?.healthy!==!0).map(n=>String(n?.name??"?"));if(r.length>0)return[`status "ready" requires every component healthy; not healthy: ${r.join(", ")} \u2014 answer "blocked" with a blocker for each, or bring them up and answer "ready" again`]}return[]}var Mf=64*1024,Ff=512*1024,MT=/[\u0000-\u0008\u000b\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;var Oye=j(require("path"));var Nl=(i=>(i.Clean="clean",i.RecipeDrift="recipe-drift",i.ChangeBrokeBringup="change-broke-bringup",i.BringupFailed="bringup-failed",i))(Nl||{}),hd=y.string().trim().min(1),Jst=y.object({url:y.string().optional().describe("the URL probed, if the check is an HTTP request"),command:y.string().optional().describe("the command run, if the check is a script \u2014 preferred when auth is needed"),headers:y.record(y.string()).optional(),status:y.union([y.number(),y.string()]).optional().describe("expected HTTP status for a url check (default 200)"),output:hd.describe("what the check returned, VERBATIM \u2014 the bytes, nothing appended; this gate RE-RUNS the check")}),Hw=y.object({schemaVersion:y.literal(1),baseUrls:y.record(y.string()).optional().describe("service \u2192 base URL of the running app; omit on a failed bring-up, never invent one"),health:Jst.optional(),teardown:hd.describe("command that tears the SUT down"),dependencies:y.record(y.boolean()).optional().describe("EVERY backing service: true = really deployed, false = mocked; REQUIRED when the app came up"),outcome:y.nativeEnum(Nl).describe("clean | recipe-drift (you corrected the recipe) | change-broke-bringup (the PR broke it) | bringup-failed (environment, not the PR)"),recipeFixes:y.array(y.string()).optional().describe("required when outcome is recipe-drift: what was corrected"),bringupError:y.object({command:hd,output:hd}).optional().describe("required when bring-up failed: the exact failing command and what it printed"),suspectFiles:y.array(y.string()).optional().describe("required for change-broke-bringup: files THIS PR changed that the failure points at, relative to your working directory (a file in another checkout of the run: its absolute path)"),seeded:y.boolean(),startedAt:hd.describe("ISO timestamp"),revisions:y.array(y.object({component:hd.describe("a shared component listed above"),url:hd.describe("the URL on the component's own origin (scheme, host and port) that answers with its deployed commit"),output:hd.describe("what the URL returned, VERBATIM; this gate FETCHES each url")})).optional().describe("only when shared components are listed above: one check per component whose deployed commit you found")});function qz(t){let e=[],r=i=>!!i&&typeof i=="object"&&!Array.isArray(i);return t.outcome!=="change-broke-bringup"&&t.outcome!=="bringup-failed"?(!r(t.baseUrls)||Object.keys(t.baseUrls).length===0?e.push("baseUrls must be a non-empty object of service \u2192 url"):Object.values(t.baseUrls).every(i=>typeof i=="string"&&i.trim())||e.push("every baseUrls value must be a non-empty url string"),r(t.health)?!(typeof t.health.url=="string"&&t.health.url.trim())&&!(typeof t.health.command=="string"&&t.health.command.trim())&&e.push("health must record a url or a command (what you actually ran)"):e.push("health must be an object"),(!r(t.dependencies)||Object.keys(t.dependencies).length===0)&&e.push("dependencies must be a non-empty object of name \u2192 boolean (real vs mocked) when the SUT came up \u2014 account for every backing service so a mocked one can't be hidden behind a green run")):(r(t.bringupError)||e.push(`outcome "${String(t.outcome)}" requires bringupError { command, output } \u2014 the exact failing bring-up command and what it printed`),t.outcome==="change-broke-bringup"&&!(Array.isArray(t.suspectFiles)&&t.suspectFiles.length>0&&t.suspectFiles.every(i=>typeof i=="string"&&i.trim()))&&e.push("change-broke-bringup requires non-empty suspectFiles[] \u2014 the changed file(s) the failure points at; if you cannot point at a file this PR changed, the outcome is bringup-failed (environment/harness), not the PR's fault")),t.outcome==="recipe-drift"&&!(Array.isArray(t.recipeFixes)&&t.recipeFixes.length>0)&&e.push("recipe-drift outcome requires a non-empty recipeFixes[] describing what was corrected"),e}var Vr=y.string().trim().min(1),Mye=(r=>(r.TestbotManaged="testbot_managed",r.CustomerDeployed="customer_deployed",r))(Mye||{}),Fye=(s=>(s.VersionEndpoint="version_endpoint",s.DeployWorkflow="deploy_workflow",s.KubernetesLabels="kubernetes_labels",s.Command="command",s.Api="api",s))(Fye||{}),zw="shared",Kst=[".skyramp/sut/setup.sh",".skyramp/sut/teardown.sh"],Zst=Vr.refine(t=>{try{let e=new URL(t);return["http:","https:"].includes(e.protocol)&&!e.username&&!e.password}catch{return!1}},"an http(s) URL with no login in it"),$z=y.object({address:Zst,readyWhen:Vr.nullable(),credentials:y.array(y.string().regex(Lz)).max(50),revisionSources:y.array(y.object({method:y.nativeEnum(Fye),detail:Vr.describe("what Testbot reads, such as GET /version or the deploy workflow's name"),components:y.array(Vr).min(1).describe("the components it tells the revision of, by name")}).strict()).max(50)}).strict(),Lye=y.object({schemaVersion:y.literal(1),type:y.nativeEnum(Mye).optional(),status:y.enum(["ready","blocked"]),environment:$z.optional(),components:y.array(y.object({name:Vr,repository:Vr.describe(`owner/repo, or "${zw}" for a customer-deployed component no repository builds`),healthy:y.boolean(),url:y.string().min(1).nullable(),...Uz,credentials:y.array(y.string().regex(Lz)).max(50).optional(),deployed:Vr.nullable().optional().describe("customer_deployed only: the revision the component runs, as setup read it (WF-SETUP-22's Deployed now), or null when it could not tell")}).strict()),suites:y.array(y.object({framework:Vr,file:Vr,result:y.enum(["pass","fail","error"])}).strict()),inputsUsed:y.array(Vr),inputsUsedHow:y.array(y.object({input:Vr,how:Vr}).strict()).optional(),inputsNotUsed:y.array(y.object({input:Vr,reason:Vr}).strict()),blockers:y.array(y.object({component:Vr,problem:Vr,evidence:Vr,fix:Vr}).strict()),replay:y.object({outcome:Vr,durationSeconds:y.number().nonnegative().nullable()}).strict().nullable(),files:y.array(y.object({path:Vr,content:y.string()}).strict())}).strict().superRefine((t,e)=>{t.inputsUsedHow?.forEach((i,s)=>{t.inputsUsed.includes(i.input)||e.addIssue({code:y.ZodIssueCode.custom,path:["inputsUsedHow",s,"input"],message:"not one of inputsUsed"})}),t.components.forEach((i,s)=>{i.credentials&&new Set(i.credentials).size!==i.credentials.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"credentials"],message:"names a credential twice"})});let r=t.type==="customer_deployed";r!==(t.environment!==void 0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["environment"],message:"an environment exactly when the plan's type is customer_deployed"}),t.environment&&new Set(t.environment.credentials).size!==t.environment.credentials.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["environment","credentials"],message:"names a credential twice"});let n=new Set(t.components.map(i=>i.name));if(t.environment?.revisionSources.forEach((i,s)=>{i.components.forEach((o,a)=>{n.has(o)||e.addIssue({code:y.ZodIssueCode.custom,path:["environment","revisionSources",s,"components",a],message:"not one of components"})})}),t.components.forEach((i,s)=>{i.deployed!==void 0!==r&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"deployed"],message:"what a component runs exactly when the plan is customer_deployed"}),i.repository===zw&&!r&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"repository"],message:`only a customer_deployed component is ${zw}`})}),r&&(t.components.forEach((i,s)=>{t.components.findIndex(o=>o.name===i.name)!==s&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"name"],message:"names a component twice"})}),t.replay!==null&&e.addIssue({code:y.ZodIssueCode.custom,path:["replay"],message:"a customer_deployed plan is never replayed"}),t.files.forEach((i,s)=>{Kst.includes(i.path)&&e.addIssue({code:y.ZodIssueCode.custom,path:["files",s,"path"],message:"a customer_deployed plan has no script that starts or stops the system"})})),r&&t.status==="ready"){let i=new Set(t.environment?.revisionSources.flatMap(s=>s.components));t.components.forEach((s,o)=>{s.repository!==zw&&!i.has(s.name)&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",o,"name"],message:"a ready customer_deployed plan reads what every component a repository builds runs"})})}});var WHt=["clean","recipe-drift"];function FT(t){let e=Oye.posix.normalize(t);return e===t&&(e===".skyramp/workspace.yml"||e.startsWith(".skyramp/sut/")&&e.length>13)}var Uye=[".skyramp/sut/setup.sh",".skyramp/sut/teardown.sh",".skyramp/sut/health.json",".skyramp/workspace.yml"];var UT=(e=>(e.GitHub="github",e))(UT||{}),jz=(s=>(s.Trigger="TRIGGER",s.Baseline="BASELINE",s.AuthoritativeRelatedChange="AUTHORITATIVE_RELATED_CHANGE",s.ConfiguredSharedDependency="CONFIGURED_SHARED_DEPENDENCY",s.ManualOverride="MANUAL_OVERRIDE",s))(jz||{}),GT=(s=>(s.PullRequest="pull_request",s.ReadyForReview="ready_for_review",s.Schedule="schedule",s.Manual="manual",s.SutSetup="sut_setup",s))(GT||{}),Xst=["sut_setup"],eot=["sut_setup","schedule"];var qT=(e=>(e.PullRequest="pull_request",e))(qT||{}),$T=(i=>(i.ModelProvider="model_provider",i.SutAccess="sut_access",i.Skyramp="skyramp",i.Other="other",i))($T||{});var HT=(i=>(i.ReportUploaded="report_uploaded",i.NoReport="no_report",i.Cancelled="cancelled",i.RecipeUploaded="recipe_uploaded",i))(HT||{}),Vye=(r=>(r.Running="running",r.Ended="ended",r))(Vye||{}),zT=(o=>(o.TimedOut="timed_out",o.AgentFailed="agent_failed",o.SetupFailed="setup_failed",o.CredentialMissing="credential_missing",o.RunnerLost="runner_lost",o.CheckoutFailed="checkout_failed",o))(zT||{}),Vz=(r=>(r.Onboard="onboard",r.Deploy="deploy",r))(Vz||{}),Wz=(r=>(r.Started="started",r.Finished="finished",r))(Wz||{}),Yz=(n=>(n.Passed="passed",n.Failed="failed",n.Skipped="skipped",n))(Yz||{});var jT=(n=>(n.ChooseCredential="choose_credential",n.FreeText="free_text",n.ChooseSource="choose_source",n))(jT||{});var VT=(n=>(n.Discover="discover",n.Start="start",n.Check="check",n))(VT||{}),WT=(i=>(i.Found="found",i.Starting="starting",i.Up="up",i.OutOfScope="out_of_scope",i))(WT||{}),Ql=y.string().regex(/^[1-9][0-9]{0,18}$/),eA=y.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/),_l=y.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),Xg=y.string().regex(/^[0-9a-f]{64}$/),LT=y.object({id:_l,revision:Ql}).strict(),As=y.object({provider:y.nativeEnum(UT),providerAccountId:Ql,providerRepositoryId:Ql}).strict(),zz=t=>`${t.provider}:${t.providerRepositoryId}`,Wye=As.extend({namespace:y.string().min(1),name:y.string().min(1)}).strict(),Gye=y.object({ref:y.string().min(1),revision:eA}).strict(),tot=y.object({repository:Wye,revision:eA,ref:y.string().nullable(),reason:y.nativeEnum(jz),change:y.object({kind:y.nativeEnum(qT),number:Ql,base:Gye.optional()}).strict().nullable(),compareWith:Gye.optional()}).strict();function rot(t){let e=t.baseline.sources,r=t.trigger.kind==="schedule"&&t.baseline.confirmedRunId!==null;if(!e)return r?"names every source of the snapshot, once":null;if(t.baseline.confirmedRunId===null)return"a run with no Confirmed Baseline names no baseline sources";let n=new Set(t.sources.map(o=>zz(o.repository))),i=new Set(e.map(o=>zz(o.repository)));return i.size===e.length&&i.size===n.size&&[...i].every(o=>n.has(o))?null:"names every source of the snapshot, once"}var not=y.object({schemaVersion:y.literal(1),runId:_l,skyrampOrgId:_l,target:LT,policy:LT.nullable(),trigger:y.object({kind:y.nativeEnum(GT),requestedAt:y.string().datetime()}).strict(),configuration:y.object({captureId:_l,revision:Ql.nullable(),hash:Xg}).strict(),baseline:y.object({confirmedRunId:_l.nullable(),sources:y.array(y.object({repository:As,revision:eA}).strict()).optional()}).strict(),sources:y.array(tot).min(1),execution:y.object({provider:y.nativeEnum(UT),repository:Wye,workflowPath:y.string(),ref:y.string()}).strict(),credentials:y.array(y.object({name:y.string(),purpose:y.nativeEnum($T),required:y.boolean()}).strict())}).strict().superRefine((t,e)=>{let r=t.trigger.kind,n=Xst.includes(r);n!==(t.policy===null)&&e.addIssue({code:y.ZodIssueCode.custom,path:["policy"],message:n?`a ${r} run has no policy`:"names the policy revision"});let i=rot(t);i&&e.addIssue({code:y.ZodIssueCode.custom,path:["baseline","sources"],message:i}),eot.includes(r)&&t.sources.forEach((s,o)=>{s.reason!=="BASELINE"&&e.addIssue({code:y.ZodIssueCode.custom,path:["sources",o,"reason"],message:`a ${r} run selects only BASELINE sources`})}),t.sources.forEach((s,o)=>{s.compareWith&&(s.reason!=="MANUAL_OVERRIDE"||s.change)&&e.addIssue({code:y.ZodIssueCode.custom,path:["sources",o,"compareWith"],message:"only a MANUAL_OVERRIDE source without a change names a revision to compare with"})})});var Jz=(r=>(r.Person="person",r.Policy="policy",r))(Jz||{}),iot=y.object({kind:y.nativeEnum(Jz),name:y.string().min(1).max(256)}).strict(),ezt=y.object({schemaVersion:y.literal(1),attempt:y.object({id:_l,number:y.number().int().positive(),deadlineAt:y.string().datetime()}).strict(),manifest:not,manifestHash:Xg,entitlements:y.array(y.string()).optional(),runToken:y.string().min(1).optional(),requestedBy:iot.nullable().optional()}).strict(),tzt=y.object({schemaVersion:y.literal(1),runId:_l,execution:y.object({provider:y.nativeEnum(UT),repository:As,providerRunId:Ql,providerRunAttempt:y.number().int().positive(),workflowRef:y.string().min(1)}).strict(),requester:y.literal(!0).optional()}).strict(),qye=y.object({repository:As,number:Ql}).strict(),sot=y.discriminatedUnion("status",[y.object({status:y.literal("none")}).strict(),y.object({status:y.literal("delivered"),pullRequests:y.array(qye).min(1)}).strict(),y.object({status:y.literal("partial"),pullRequests:y.array(qye).min(1),failures:y.array(y.object({repository:As,message:y.string()}).strict()).min(1)}).strict(),y.object({status:y.literal("failed"),message:y.string()}).strict()]),oot=y.object({sufficiency:y.nativeEnum(Gw),rationale:y.string().min(1),gaps:y.array(y.string().min(1)),acceptedEvidence:y.array(y.object({kind:y.nativeEnum(fd),repository:y.string().min(1),revision:eA,reference:y.string().min(1),summary:y.string().min(1)}).strict()),actionRequired:y.array(y.nativeEnum(qw))}).strict().superRefine((t,e)=>{t.sufficiency==="sufficient"!=(t.gaps.length===0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["gaps"],message:"sufficient evidence has no gaps, and insufficient evidence names at least one"}),new Set(t.actionRequired).size!==t.actionRequired.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["actionRequired"],message:"a reason appears twice"})}),Zg=500,Kz=2048,Zz=1e3,aot=y.object({testResults:y.array(y.object({resultId:y.string().regex(/^[^\u0000-\u001f]{1,512}$/),repository:y.string().regex(/^[A-Za-z0-9._-]{1,100}\/[A-Za-z0-9._-]{1,100}$/),testType:y.string(),endpoint:y.string(),status:y.enum(["Pass","Fail","Skipped"]),details:y.string(),fileName:y.string().optional(),testId:y.string().regex(/^[^\u0000-\u001f]{1,512}$/).optional(),failureCause:y.object({kind:y.nativeEnum(QT),family:y.nativeEnum(PT).optional()}).strict().optional()}).strict()),validation:oot,changes:y.array(y.object({id:y.string().min(1).max(512),text:y.string().max(16384),source:y.string().max(Kz),testedBy:y.array(y.string().min(1).max(1024)).max(Zg),writtenBy:y.array(y.string().min(1).max(1024)).max(Zg),maintainedBy:y.array(y.string().min(1).max(1024)).max(Zg)}).strict()).max(Zz).optional(),traceVersion:y.literal(1)}).passthrough().superRefine((t,e)=>{let r=new Set;t.testResults.forEach((n,i)=>{let s=n.failureCause;s&&n.status==="Pass"&&e.addIssue({code:y.ZodIssueCode.custom,path:["testResults",i,"failureCause"],message:"a passing result has no failure cause"}),s&&s.kind==="environment"!=(s.family!==void 0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["testResults",i,"failureCause"],message:"an environment cause names its family, and no other cause does"});let o=["testResults",i,"resultId"],a=n.resultId.slice(`${n.repository}:${n.testType}:`.length);(!n.resultId.startsWith(`${n.repository}:${n.testType}:`)||a===""||a.startsWith("/")||a.startsWith("#"))&&e.addIssue({code:y.ZodIssueCode.custom,path:o,message:"is not repository:testType:path for this result"}),r.has(n.resultId)&&e.addIssue({code:y.ZodIssueCode.custom,path:o,message:"stable identity repeated"}),r.add(n.resultId)})}),$ye=t=>t.replace(/[%:#]/g,e=>encodeURIComponent(e));function Xz(t,e,r,n){let i=r.replace(/\\/g,"/"),s=i.split("/").filter(c=>c!==""&&c!==".");if(i.startsWith("/")||/^[A-Za-z]:/.test(i)||s.length===0||s.includes(".."))throw new Error(`testResultId needs a path relative to the repository root, got "${r}"`);let o=s.join("/"),a=`${t}:${e}:${$ye(o)}`;return n?`${a}#${$ye(n)}`:a}var Yye=50,Hye=y.string().regex(/^(?!.*\.\.)(?!\/)(?!.*\/$)[A-Za-z0-9._/-]{1,255}$/),Jye=y.discriminatedUnion("kind",[y.object({kind:y.literal("branch_pushed"),repository:As,branch:Hye,commit:eA}).strict(),y.object({kind:y.enum(["pull_request_opened","pull_request_edited"]),repository:As,number:Ql,branch:Hye}).strict()]),cot=y.object({schemaVersion:y.literal(1),run:y.object({runId:_l,attemptNumber:y.number().int().positive(),manifestHash:Xg}).strict(),target:LT,policy:LT,provenance:y.object({sources:y.array(y.object({repository:As,revision:eA}).strict())}).strict(),delivery:y.object({generatedTests:sot}).strict(),producer:y.object({testbot:y.string().regex(/^[0-9A-Za-z.+-]{1,64}$/),mcp:y.string().regex(/^[0-9A-Za-z.+-]{1,64}$/)}).strict(),report:aot,githubWrites:y.array(Jye).max(Yye).optional()}).strict(),rzt=cot.pick({schemaVersion:!0,run:!0,target:!0,provenance:!0,producer:!0}).extend({recipe:Lye}).strict().superRefine(({recipe:t},e)=>{let r=(s,o)=>e.addIssue({code:y.ZodIssueCode.custom,path:["recipe",...s],message:o});t.status==="blocked"&&t.blockers.length===0&&r(["blockers"],"a blocked recipe names at least one blocker");let n=new Set,i=0;t.files.forEach((s,o)=>{FT(s.path)||r(["files",o,"path"],"is not .skyramp/workspace.yml or a file under .skyramp/sut/"),n.has(s.path)&&r(["files",o,"path"],"file repeated"),n.add(s.path),MT.test(s.content)&&r(["files",o,"content"],"is not text");let a=Buffer.byteLength(s.content,"utf8");i+=a,a>Mf&&r(["files",o,"content"],`larger than ${Mf} bytes`)}),i>Ff&&r(["files"],`recipe text over ${Ff} bytes in total`)}),lot=y.object({schemaVersion:y.literal(1),stage:y.nativeEnum(Vz),event:y.nativeEnum(Wz),status:y.nativeEnum(Yz).optional()}).strict().refine(t=>t.status===void 0||t.event==="finished",{path:["status"],message:"only a finished stage has a status"}),Vw=100,Kye=5e3,Hz=2e3,zye=100,Zye=/^[A-Za-z0-9_-]{1,64}$/,uot=20,dot=200,Xye=100,pot=100,fot=200,hot=500,ej=/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/,mc=t=>y.string().max(t).refine(e=>e.trim().length>0&&!ej.test(e),"blank, or not text"),jw={sequence:y.number().int().min(1).max(Kye),at:y.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/)},eEe=y.discriminatedUnion("kind",[y.object({...jw,kind:y.literal("log"),phase:y.nativeEnum(VT),text:mc(Hz)}).strict(),y.object({...jw,kind:y.literal("component"),name:mc(zye),repository:mc(fot).refine(t=>/^[^/\s]+\/[^/\s]+$/.test(t),"not owner/name"),file:mc(hot).nullable(),status:y.nativeEnum(WT),version:mc(pot).optional()}).strict(),y.object({...jw,kind:y.literal("reply"),to:y.string().uuid(),accepted:y.boolean(),text:mc(Hz)}).strict(),y.object({...jw,kind:y.literal("question"),id:y.string().regex(Zye),type:y.nativeEnum(jT),text:mc(Hz),component:mc(zye).nullable(),choices:y.array(mc(dot)).max(uot),placeholder:mc(Xye).optional()}).strict(),y.object({...jw,kind:y.literal("delivered"),ids:y.array(y.string().uuid()).max(Vw)}).strict()]).superRefine((t,e)=>{t.kind==="question"&&(t.type==="free_text"!=(t.choices.length===0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["choices"],message:"choices exactly when the question is not free_text"}),new Set(t.choices).size!==t.choices.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["choices"],message:"a choice twice"}))}),mot=y.object({schemaVersion:y.literal(1),events:y.array(eEe).max(Vw)}).strict(),jye={id:y.string().uuid(),text:y.string(),by:y.string().nullable(),at:y.string()},got=y.discriminatedUnion("kind",[y.object({...jye,kind:y.literal("instruction"),question:y.null()}),y.object({...jye,kind:y.literal("answer"),question:y.string().regex(Zye)})]),Aot=y.object({schemaVersion:y.literal(1),leftOut:y.array(y.string()),messages:y.array(got).optional()}),yot=y.object({schemaVersion:y.literal(1),configuration:y.object({captureId:_l,revision:Ql.nullable(),hash:Xg}).strict(),capture:y.object({schemaVersion:y.literal(1),settings:y.object({target:y.object({environment:y.unknown()}).passthrough(),timeoutMinutes:y.number().int().positive()}).passthrough(),provenance:y.object({}).passthrough(),hash:Xg}).strict()}).strict(),Eot=$z.extend({version:y.number().int().positive(),components:y.array(y.object({name:y.string().min(1),repository:y.string().min(1)}).strict())}).strict(),bot=y.object({schemaVersion:y.literal(1),testEnvironment:Eot.nullable().optional(),runtimePlan:y.object({version:y.number().int().positive(),contentHash:Xg,files:y.array(y.object({path:y.string().refine(FT,"not a recipe file path"),content:y.string()}).strict()).min(1)}).strict().nullable()}).strict().refine(t=>!(t.runtimePlan&&t.testEnvironment),{message:"a run pins a recipe or a customer's Test Environment, never both",path:["testEnvironment"]}),wot=y.object({schemaVersion:y.literal(1),state:y.nativeEnum(Vye),ending:y.nativeEnum(HT).nullable(),cause:y.nativeEnum(zT).nullable(),deadlineAt:y.string().datetime()}).strict();function tEe(t){return t.reportUploaded?{schemaVersion:1,reason:"report_uploaded",cause:null}:t.recipeUploaded?{schemaVersion:1,reason:"recipe_uploaded",cause:null}:t.cancelled?{schemaVersion:1,reason:"cancelled",cause:null}:{schemaVersion:1,reason:"no_report",cause:Cot(t)}}function Cot(t){return t.credentialMissing?"credential_missing":t.checkoutFailed?"checkout_failed":t.setupFailed?"setup_failed":t.timedOut?"timed_out":"agent_failed"}var Iot=["generate-unit","native-run","finalize"],Sot=["preflight","plan","write",...Iot,"report","deliver"];var tA=(n=>(n.Unit="unit",n.Integration="integration",n.E2e="e2e",n))(tA||{});var YT=1440;dt();Pz();Of();var rEe;(function(t){t[t.lineFeed=10]="lineFeed",t[t.carriageReturn=13]="carriageReturn",t[t.space=32]="space",t[t._0=48]="_0",t[t._1=49]="_1",t[t._2=50]="_2",t[t._3=51]="_3",t[t._4=52]="_4",t[t._5=53]="_5",t[t._6=54]="_6",t[t._7=55]="_7",t[t._8=56]="_8",t[t._9=57]="_9",t[t.a=97]="a",t[t.b=98]="b",t[t.c=99]="c",t[t.d=100]="d",t[t.e=101]="e",t[t.f=102]="f",t[t.g=103]="g",t[t.h=104]="h",t[t.i=105]="i",t[t.j=106]="j",t[t.k=107]="k",t[t.l=108]="l",t[t.m=109]="m",t[t.n=110]="n",t[t.o=111]="o",t[t.p=112]="p",t[t.q=113]="q",t[t.r=114]="r",t[t.s=115]="s",t[t.t=116]="t",t[t.u=117]="u",t[t.v=118]="v",t[t.w=119]="w",t[t.x=120]="x",t[t.y=121]="y",t[t.z=122]="z",t[t.A=65]="A",t[t.B=66]="B",t[t.C=67]="C",t[t.D=68]="D",t[t.E=69]="E",t[t.F=70]="F",t[t.G=71]="G",t[t.H=72]="H",t[t.I=73]="I",t[t.J=74]="J",t[t.K=75]="K",t[t.L=76]="L",t[t.M=77]="M",t[t.N=78]="N",t[t.O=79]="O",t[t.P=80]="P",t[t.Q=81]="Q",t[t.R=82]="R",t[t.S=83]="S",t[t.T=84]="T",t[t.U=85]="U",t[t.V=86]="V",t[t.W=87]="W",t[t.X=88]="X",t[t.Y=89]="Y",t[t.Z=90]="Z",t[t.asterisk=42]="asterisk",t[t.backslash=92]="backslash",t[t.closeBrace=125]="closeBrace",t[t.closeBracket=93]="closeBracket",t[t.colon=58]="colon",t[t.comma=44]="comma",t[t.dot=46]="dot",t[t.doubleQuote=34]="doubleQuote",t[t.minus=45]="minus",t[t.openBrace=123]="openBrace",t[t.openBracket=91]="openBracket",t[t.plus=43]="plus",t[t.slash=47]="slash",t[t.formFeed=12]="formFeed",t[t.tab=9]="tab"})(rEe||(rEe={}));var vot=new Array(20).fill(0).map((t,e)=>" ".repeat(e)),rA=200,Bot={" ":{"\n":new Array(rA).fill(0).map((t,e)=>`
|
|
215
|
+
<sub>[${Et().workflowRunLinkLabel}](${e})</sub>`}_T();_T();_T();Of();function Fz(t,e){if(process.env.GITHUB_ACTIONS)return new Jg(t,Pye,e);throw new Error("Unrecognized CI environment. Set GITHUB_ACTIONS=true for GitHub Actions, or use EvalPlatform directly for eval/testing.")}dt();var Gw=(r=>(r.Sufficient="sufficient",r.Insufficient="insufficient",r))(Gw||{}),qw=(d=>(d.RelatedChangeConflict="related_change_conflict",d.ReferenceOutsideTarget="reference_outside_target",d.SourceAccessLost="source_access_lost",d.ConfigurationIncomplete="configuration_incomplete",d.CredentialUnavailable="credential_unavailable",d.WorkflowBindingUnverified="workflow_binding_unverified",d.WorkflowRefUnprotected="workflow_ref_unprotected",d.DeploymentReview="deployment_review",d.SutRevisionMismatch="sut_revision_mismatch",d.IsolationUnavailable="isolation_unavailable",d.EvidenceInsufficient="evidence_insufficient",d))(qw||{}),fd=(s=>(s.CiCheck="ci_check",s.TestReport="test_report",s.StaticAnalysis="static_analysis",s.CodeReview="code_review",s.Other="other",s))(fd||{}),QT=(n=>(n.Application="application",n.Environment="environment",n.TestDefect="test_defect",n))(QT||{}),PT=(a=>(a.AuthToken="auth_token",a.Secret="secret",a.DataConnection="data_connection",a.AppNotStarted="app_not_started",a.Login="login",a.ExternalDependency="external_dependency",a.RecordingReplay="recording_replay",a))(PT||{});var DT=(n=>(n.Seed="seed",n.RuntimeMock="runtime_mock",n.EnvOverride="env_override",n))(DT||{}),OT=(n=>(n.TestCode="test_code",n.SkyrampMocker="skyramp_mocker",n.RecipeOverride="recipe_override",n))(OT||{});var Kg=(r=>(r.Ready="ready",r.Blocked="blocked",r))(Kg||{}),Dn=y.string().trim().min(1),Hst=y.object({action:y.enum(["start","run","wait"]),text:Dn,source:y.enum(["file","notes","testbot"]).describe("file: a file in the repository; notes: the Target's notes; testbot: Testbot's own finding"),file:Dn.nullable().describe("the file the step came from, relative to the component's repository; null unless source is file")}).strict().refine(t=>t.source==="file"==(t.file!==null),{path:["file"],message:"a file exactly when the step came from one"}),zst=/^[A-Za-z_][A-Za-z0-9_]*$/,Lz=/^(?!GITHUB_)(?!SKYRAMP_RUNNER_)[A-Z][A-Z0-9_]{0,99}$/,Uz={steps:y.array(Hst).max(20).optional().describe("how it starts, in order"),kind:y.enum(["web_app","service","database","external_service"]).optional(),from:y.object({file:Dn,service:Dn.nullable()}).strict().optional(),credentials:y.array(y.string().max(100).regex(zst)).max(50).optional().describe("the Target's credentials this component's recipe uses: a sign-in (a test user, password or token) or an API key, which the workflow supplies from a GitHub Actions secret as the environment variable of the credential's name; give each name exactly as the recipe reads it. Names only, never a value, and not a secret the recipe generates itself")},jst=y.object({name:Dn,repository:Dn.describe("owner/repo of the repository the component is built from"),healthy:y.boolean(),...Uz}),Vst=y.object({component:Dn,problem:Dn,evidence:Dn.describe("the exact command and output that shows it"),fix:Dn.describe("what the user must provide, and where")}),Wst=y.object({framework:Dn,file:Dn.describe("the test file run, relative to its repository root"),result:y.enum(["pass","fail","error"])}),Yst=y.object({input:Dn.describe("the part of the user's SUT input, as given"),reason:Dn}),$w=y.object({schemaVersion:y.literal(1),status:y.nativeEnum(Kg).describe("ready only if every component came up healthy and the recipe is written"),components:y.array(jst),suites:y.array(Wst).default([]).describe("one run per test suite the Target's repositories have; empty when they have none"),inputsUsed:y.array(Dn).default([]).describe("the parts of the user's SUT input the recipe used"),inputsUsedHow:y.array(y.object({input:Dn.describe("exactly as written in inputsUsed; an entry that is not there is left out"),how:Dn.describe("what the recipe did with it")})).optional(),inputsNotUsed:y.array(Yst).default([]).describe("the parts it did not use, and why"),blockers:y.array(Vst).describe("required (non-empty) when status is blocked")});function Gz(t){if(t.status==="blocked"&&!(Array.isArray(t.blockers)&&t.blockers.length>0))return['status "blocked" requires at least one blocker { component, problem, evidence, fix } \u2014 say what stopped the bring-up'];if(t.status==="ready"){let e=Array.isArray(t.components)?t.components:[];if(e.length===0)return['status "ready" requires at least one component \u2014 name each component the recipe brought up healthy'];let r=e.filter(n=>n?.healthy!==!0).map(n=>String(n?.name??"?"));if(r.length>0)return[`status "ready" requires every component healthy; not healthy: ${r.join(", ")} \u2014 answer "blocked" with a blocker for each, or bring them up and answer "ready" again`]}return[]}var Mf=64*1024,Ff=512*1024,MT=/[\u0000-\u0008\u000b\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;var Oye=j(require("path"));var Nl=(i=>(i.Clean="clean",i.RecipeDrift="recipe-drift",i.ChangeBrokeBringup="change-broke-bringup",i.BringupFailed="bringup-failed",i))(Nl||{}),hd=y.string().trim().min(1),Jst=y.object({url:y.string().optional().describe("the URL probed, if the check is an HTTP request"),command:y.string().optional().describe("the command run, if the check is a script \u2014 preferred when auth is needed"),headers:y.record(y.string()).optional(),status:y.union([y.number(),y.string()]).optional().describe("expected HTTP status for a url check (default 200)"),output:hd.describe("what the check returned, VERBATIM \u2014 the bytes, nothing appended; this gate RE-RUNS the check")}),Hw=y.object({schemaVersion:y.literal(1),baseUrls:y.record(y.string()).optional().describe("service \u2192 base URL of the running app; omit on a failed bring-up, never invent one"),health:Jst.optional(),teardown:hd.describe("command that tears the SUT down"),dependencies:y.record(y.boolean()).optional().describe("EVERY backing service: true = really deployed, false = mocked; REQUIRED when the app came up"),outcome:y.nativeEnum(Nl).describe("clean | recipe-drift (you corrected the recipe) | change-broke-bringup (the PR broke it) | bringup-failed (environment, not the PR)"),recipeFixes:y.array(y.string()).optional().describe("required when outcome is recipe-drift: what was corrected"),bringupError:y.object({command:hd,output:hd}).optional().describe("required when bring-up failed: the exact failing command and what it printed"),suspectFiles:y.array(y.string()).optional().describe("required for change-broke-bringup: files THIS PR changed that the failure points at, relative to your working directory (a file in another checkout of the run: its absolute path)"),seeded:y.boolean(),startedAt:hd.describe("ISO timestamp"),revisions:y.array(y.object({component:hd.describe("a shared component listed above"),url:hd.describe("the URL on the component's own origin (scheme, host and port) that answers with its deployed commit"),output:hd.describe("what the URL returned, VERBATIM; this gate FETCHES each url")})).optional().describe("only when shared components are listed above: one check per component whose deployed commit you found")});function qz(t){let e=[],r=i=>!!i&&typeof i=="object"&&!Array.isArray(i);return t.outcome!=="change-broke-bringup"&&t.outcome!=="bringup-failed"?(!r(t.baseUrls)||Object.keys(t.baseUrls).length===0?e.push("baseUrls must be a non-empty object of service \u2192 url"):Object.values(t.baseUrls).every(i=>typeof i=="string"&&i.trim())||e.push("every baseUrls value must be a non-empty url string"),r(t.health)?!(typeof t.health.url=="string"&&t.health.url.trim())&&!(typeof t.health.command=="string"&&t.health.command.trim())&&e.push("health must record a url or a command (what you actually ran)"):e.push("health must be an object"),(!r(t.dependencies)||Object.keys(t.dependencies).length===0)&&e.push("dependencies must be a non-empty object of name \u2192 boolean (real vs mocked) when the SUT came up \u2014 account for every backing service so a mocked one can't be hidden behind a green run")):(r(t.bringupError)||e.push(`outcome "${String(t.outcome)}" requires bringupError { command, output } \u2014 the exact failing bring-up command and what it printed`),t.outcome==="change-broke-bringup"&&!(Array.isArray(t.suspectFiles)&&t.suspectFiles.length>0&&t.suspectFiles.every(i=>typeof i=="string"&&i.trim()))&&e.push("change-broke-bringup requires non-empty suspectFiles[] \u2014 the changed file(s) the failure points at; if you cannot point at a file this PR changed, the outcome is bringup-failed (environment/harness), not the PR's fault")),t.outcome==="recipe-drift"&&!(Array.isArray(t.recipeFixes)&&t.recipeFixes.length>0)&&e.push("recipe-drift outcome requires a non-empty recipeFixes[] describing what was corrected"),e}var Vr=y.string().trim().min(1),Mye=(r=>(r.TestbotManaged="testbot_managed",r.CustomerDeployed="customer_deployed",r))(Mye||{}),Fye=(s=>(s.VersionEndpoint="version_endpoint",s.DeployWorkflow="deploy_workflow",s.KubernetesLabels="kubernetes_labels",s.Command="command",s.Api="api",s))(Fye||{}),zw="shared",Kst=[".skyramp/sut/setup.sh",".skyramp/sut/teardown.sh"],Zst=Vr.refine(t=>{try{let e=new URL(t);return["http:","https:"].includes(e.protocol)&&!e.username&&!e.password}catch{return!1}},"an http(s) URL with no login in it"),$z=y.object({address:Zst,readyWhen:Vr.nullable(),credentials:y.array(y.string().regex(Lz)).max(50),revisionSources:y.array(y.object({method:y.nativeEnum(Fye),detail:Vr.describe("what Testbot reads, such as GET /version or the deploy workflow's name"),components:y.array(Vr).min(1).describe("the components it tells the revision of, by name")}).strict()).max(50)}).strict(),Lye=y.object({schemaVersion:y.literal(1),type:y.nativeEnum(Mye).optional(),status:y.enum(["ready","blocked"]),environment:$z.optional(),components:y.array(y.object({name:Vr,repository:Vr.describe(`owner/repo, or "${zw}" for a customer-deployed component no repository builds`),healthy:y.boolean(),url:y.string().min(1).nullable(),...Uz,credentials:y.array(y.string().regex(Lz)).max(50).optional(),deployed:Vr.nullable().optional().describe("customer_deployed only: the revision the component runs, as setup read it (WF-SETUP-22's Deployed now), or null when it could not tell")}).strict()),suites:y.array(y.object({framework:Vr,file:Vr,result:y.enum(["pass","fail","error"])}).strict()),inputsUsed:y.array(Vr),inputsUsedHow:y.array(y.object({input:Vr,how:Vr}).strict()).optional(),inputsNotUsed:y.array(y.object({input:Vr,reason:Vr}).strict()),blockers:y.array(y.object({component:Vr,problem:Vr,evidence:Vr,fix:Vr}).strict()),replay:y.object({outcome:Vr,durationSeconds:y.number().nonnegative().nullable()}).strict().nullable(),files:y.array(y.object({path:Vr,content:y.string()}).strict())}).strict().superRefine((t,e)=>{t.inputsUsedHow?.forEach((i,s)=>{t.inputsUsed.includes(i.input)||e.addIssue({code:y.ZodIssueCode.custom,path:["inputsUsedHow",s,"input"],message:"not one of inputsUsed"})}),t.components.forEach((i,s)=>{i.credentials&&new Set(i.credentials).size!==i.credentials.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"credentials"],message:"names a credential twice"})});let r=t.type==="customer_deployed";r!==(t.environment!==void 0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["environment"],message:"an environment exactly when the plan's type is customer_deployed"}),t.environment&&new Set(t.environment.credentials).size!==t.environment.credentials.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["environment","credentials"],message:"names a credential twice"});let n=new Set(t.components.map(i=>i.name));if(t.environment?.revisionSources.forEach((i,s)=>{i.components.forEach((o,a)=>{n.has(o)||e.addIssue({code:y.ZodIssueCode.custom,path:["environment","revisionSources",s,"components",a],message:"not one of components"})})}),t.components.forEach((i,s)=>{i.deployed!==void 0!==r&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"deployed"],message:"what a component runs exactly when the plan is customer_deployed"}),i.repository===zw&&!r&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"repository"],message:`only a customer_deployed component is ${zw}`})}),r&&(t.components.forEach((i,s)=>{t.components.findIndex(o=>o.name===i.name)!==s&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",s,"name"],message:"names a component twice"})}),t.replay!==null&&e.addIssue({code:y.ZodIssueCode.custom,path:["replay"],message:"a customer_deployed plan is never replayed"}),t.files.forEach((i,s)=>{Kst.includes(i.path)&&e.addIssue({code:y.ZodIssueCode.custom,path:["files",s,"path"],message:"a customer_deployed plan has no script that starts or stops the system"})})),r&&t.status==="ready"){let i=new Set(t.environment?.revisionSources.flatMap(s=>s.components));t.components.forEach((s,o)=>{s.repository!==zw&&!i.has(s.name)&&e.addIssue({code:y.ZodIssueCode.custom,path:["components",o,"name"],message:"a ready customer_deployed plan reads what every component a repository builds runs"})})}});var WHt=["clean","recipe-drift"];function FT(t){let e=Oye.posix.normalize(t);return e===t&&(e===".skyramp/workspace.yml"||e.startsWith(".skyramp/sut/")&&e.length>13)}var Uye=[".skyramp/sut/setup.sh",".skyramp/sut/teardown.sh",".skyramp/sut/health.json",".skyramp/workspace.yml"];var UT=(e=>(e.GitHub="github",e))(UT||{}),jz=(s=>(s.Trigger="TRIGGER",s.Baseline="BASELINE",s.AuthoritativeRelatedChange="AUTHORITATIVE_RELATED_CHANGE",s.ConfiguredSharedDependency="CONFIGURED_SHARED_DEPENDENCY",s.ManualOverride="MANUAL_OVERRIDE",s))(jz||{}),GT=(s=>(s.PullRequest="pull_request",s.ReadyForReview="ready_for_review",s.Schedule="schedule",s.Manual="manual",s.SutSetup="sut_setup",s))(GT||{}),Xst=["sut_setup"],eot=["sut_setup","schedule"];var qT=(e=>(e.PullRequest="pull_request",e))(qT||{}),$T=(i=>(i.ModelProvider="model_provider",i.SutAccess="sut_access",i.Skyramp="skyramp",i.Other="other",i))($T||{});var HT=(i=>(i.ReportUploaded="report_uploaded",i.NoReport="no_report",i.Cancelled="cancelled",i.RecipeUploaded="recipe_uploaded",i))(HT||{}),Vye=(r=>(r.Running="running",r.Ended="ended",r))(Vye||{}),zT=(o=>(o.TimedOut="timed_out",o.AgentFailed="agent_failed",o.SetupFailed="setup_failed",o.CredentialMissing="credential_missing",o.RunnerLost="runner_lost",o.CheckoutFailed="checkout_failed",o))(zT||{}),Vz=(r=>(r.Onboard="onboard",r.Deploy="deploy",r))(Vz||{}),Wz=(r=>(r.Started="started",r.Finished="finished",r))(Wz||{}),Yz=(n=>(n.Passed="passed",n.Failed="failed",n.Skipped="skipped",n))(Yz||{});var jT=(n=>(n.ChooseCredential="choose_credential",n.FreeText="free_text",n.ChooseSource="choose_source",n))(jT||{});var VT=(n=>(n.Discover="discover",n.Start="start",n.Check="check",n))(VT||{}),WT=(i=>(i.Found="found",i.Starting="starting",i.Up="up",i.OutOfScope="out_of_scope",i))(WT||{}),Ql=y.string().regex(/^[1-9][0-9]{0,18}$/),eA=y.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/),_l=y.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/),Xg=y.string().regex(/^[0-9a-f]{64}$/),LT=y.object({id:_l,revision:Ql}).strict(),As=y.object({provider:y.nativeEnum(UT),providerAccountId:Ql,providerRepositoryId:Ql}).strict(),zz=t=>`${t.provider}:${t.providerRepositoryId}`,Wye=As.extend({namespace:y.string().min(1),name:y.string().min(1)}).strict(),Gye=y.object({ref:y.string().min(1),revision:eA}).strict(),tot=y.object({repository:Wye,revision:eA,ref:y.string().nullable(),reason:y.nativeEnum(jz),change:y.object({kind:y.nativeEnum(qT),number:Ql,base:Gye.optional()}).strict().nullable(),compareWith:Gye.optional()}).strict();function rot(t){let e=t.baseline.sources,r=t.trigger.kind==="schedule"&&t.baseline.confirmedRunId!==null;if(!e)return r?"names every source of the snapshot, once":null;if(t.baseline.confirmedRunId===null)return"a run with no Confirmed Baseline names no baseline sources";let n=new Set(t.sources.map(o=>zz(o.repository))),i=new Set(e.map(o=>zz(o.repository)));return i.size===e.length&&i.size===n.size&&[...i].every(o=>n.has(o))?null:"names every source of the snapshot, once"}var not=y.object({schemaVersion:y.literal(1),runId:_l,skyrampOrgId:_l,target:LT,policy:LT.nullable(),trigger:y.object({kind:y.nativeEnum(GT),requestedAt:y.string().datetime()}).strict(),configuration:y.object({captureId:_l,revision:Ql.nullable(),hash:Xg}).strict(),baseline:y.object({confirmedRunId:_l.nullable(),sources:y.array(y.object({repository:As,revision:eA}).strict()).optional()}).strict(),sources:y.array(tot).min(1),execution:y.object({provider:y.nativeEnum(UT),repository:Wye,workflowPath:y.string(),ref:y.string()}).strict(),credentials:y.array(y.object({name:y.string(),purpose:y.nativeEnum($T),required:y.boolean()}).strict())}).strict().superRefine((t,e)=>{let r=t.trigger.kind,n=Xst.includes(r);n!==(t.policy===null)&&e.addIssue({code:y.ZodIssueCode.custom,path:["policy"],message:n?`a ${r} run has no policy`:"names the policy revision"});let i=rot(t);i&&e.addIssue({code:y.ZodIssueCode.custom,path:["baseline","sources"],message:i}),eot.includes(r)&&t.sources.forEach((s,o)=>{s.reason!=="BASELINE"&&e.addIssue({code:y.ZodIssueCode.custom,path:["sources",o,"reason"],message:`a ${r} run selects only BASELINE sources`})}),t.sources.forEach((s,o)=>{s.compareWith&&(s.reason!=="MANUAL_OVERRIDE"||s.change)&&e.addIssue({code:y.ZodIssueCode.custom,path:["sources",o,"compareWith"],message:"only a MANUAL_OVERRIDE source without a change names a revision to compare with"})})});var Jz=(r=>(r.Person="person",r.Policy="policy",r))(Jz||{}),iot=y.object({kind:y.nativeEnum(Jz),name:y.string().min(1).max(256)}).strict(),ezt=y.object({schemaVersion:y.literal(1),attempt:y.object({id:_l,number:y.number().int().positive(),deadlineAt:y.string().datetime()}).strict(),manifest:not,manifestHash:Xg,entitlements:y.array(y.string()).optional(),runToken:y.string().min(1).optional(),requestedBy:iot.nullable().optional(),writeAllowed:y.boolean().optional()}).strict(),tzt=y.object({schemaVersion:y.literal(1),runId:_l,execution:y.object({provider:y.nativeEnum(UT),repository:As,providerRunId:Ql,providerRunAttempt:y.number().int().positive(),workflowRef:y.string().min(1)}).strict(),requester:y.literal(!0).optional(),writeCheck:y.literal(!0).optional()}).strict(),qye=y.object({repository:As,number:Ql}).strict(),sot=y.discriminatedUnion("status",[y.object({status:y.literal("none")}).strict(),y.object({status:y.literal("delivered"),pullRequests:y.array(qye).min(1)}).strict(),y.object({status:y.literal("partial"),pullRequests:y.array(qye).min(1),failures:y.array(y.object({repository:As,message:y.string()}).strict()).min(1)}).strict(),y.object({status:y.literal("failed"),message:y.string()}).strict()]),oot=y.object({sufficiency:y.nativeEnum(Gw),rationale:y.string().min(1),gaps:y.array(y.string().min(1)),acceptedEvidence:y.array(y.object({kind:y.nativeEnum(fd),repository:y.string().min(1),revision:eA,reference:y.string().min(1),summary:y.string().min(1)}).strict()),actionRequired:y.array(y.nativeEnum(qw))}).strict().superRefine((t,e)=>{t.sufficiency==="sufficient"!=(t.gaps.length===0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["gaps"],message:"sufficient evidence has no gaps, and insufficient evidence names at least one"}),new Set(t.actionRequired).size!==t.actionRequired.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["actionRequired"],message:"a reason appears twice"})}),Zg=500,Kz=2048,Zz=1e3,aot=y.object({testResults:y.array(y.object({resultId:y.string().regex(/^[^\u0000-\u001f]{1,512}$/),repository:y.string().regex(/^[A-Za-z0-9._-]{1,100}\/[A-Za-z0-9._-]{1,100}$/),testType:y.string(),endpoint:y.string(),status:y.enum(["Pass","Fail","Skipped"]),details:y.string(),fileName:y.string().optional(),testId:y.string().regex(/^[^\u0000-\u001f]{1,512}$/).optional(),failureCause:y.object({kind:y.nativeEnum(QT),family:y.nativeEnum(PT).optional()}).strict().optional()}).strict()),validation:oot,changes:y.array(y.object({id:y.string().min(1).max(512),text:y.string().max(16384),source:y.string().max(Kz),testedBy:y.array(y.string().min(1).max(1024)).max(Zg),writtenBy:y.array(y.string().min(1).max(1024)).max(Zg),maintainedBy:y.array(y.string().min(1).max(1024)).max(Zg)}).strict()).max(Zz).optional(),traceVersion:y.literal(1)}).passthrough().superRefine((t,e)=>{let r=new Set;t.testResults.forEach((n,i)=>{let s=n.failureCause;s&&n.status==="Pass"&&e.addIssue({code:y.ZodIssueCode.custom,path:["testResults",i,"failureCause"],message:"a passing result has no failure cause"}),s&&s.kind==="environment"!=(s.family!==void 0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["testResults",i,"failureCause"],message:"an environment cause names its family, and no other cause does"});let o=["testResults",i,"resultId"],a=n.resultId.slice(`${n.repository}:${n.testType}:`.length);(!n.resultId.startsWith(`${n.repository}:${n.testType}:`)||a===""||a.startsWith("/")||a.startsWith("#"))&&e.addIssue({code:y.ZodIssueCode.custom,path:o,message:"is not repository:testType:path for this result"}),r.has(n.resultId)&&e.addIssue({code:y.ZodIssueCode.custom,path:o,message:"stable identity repeated"}),r.add(n.resultId)})}),$ye=t=>t.replace(/[%:#]/g,e=>encodeURIComponent(e));function Xz(t,e,r,n){let i=r.replace(/\\/g,"/"),s=i.split("/").filter(c=>c!==""&&c!==".");if(i.startsWith("/")||/^[A-Za-z]:/.test(i)||s.length===0||s.includes(".."))throw new Error(`testResultId needs a path relative to the repository root, got "${r}"`);let o=s.join("/"),a=`${t}:${e}:${$ye(o)}`;return n?`${a}#${$ye(n)}`:a}var Yye=50,Hye=y.string().regex(/^(?!.*\.\.)(?!\/)(?!.*\/$)[A-Za-z0-9._/-]{1,255}$/),Jye=y.discriminatedUnion("kind",[y.object({kind:y.literal("branch_pushed"),repository:As,branch:Hye,commit:eA}).strict(),y.object({kind:y.enum(["pull_request_opened","pull_request_edited"]),repository:As,number:Ql,branch:Hye}).strict()]),cot=y.object({schemaVersion:y.literal(1),run:y.object({runId:_l,attemptNumber:y.number().int().positive(),manifestHash:Xg}).strict(),target:LT,policy:LT,provenance:y.object({sources:y.array(y.object({repository:As,revision:eA}).strict())}).strict(),delivery:y.object({generatedTests:sot}).strict(),producer:y.object({testbot:y.string().regex(/^[0-9A-Za-z.+-]{1,64}$/),mcp:y.string().regex(/^[0-9A-Za-z.+-]{1,64}$/)}).strict(),report:aot,githubWrites:y.array(Jye).max(Yye).optional()}).strict(),rzt=cot.pick({schemaVersion:!0,run:!0,target:!0,provenance:!0,producer:!0}).extend({recipe:Lye}).strict().superRefine(({recipe:t},e)=>{let r=(s,o)=>e.addIssue({code:y.ZodIssueCode.custom,path:["recipe",...s],message:o});t.status==="blocked"&&t.blockers.length===0&&r(["blockers"],"a blocked recipe names at least one blocker");let n=new Set,i=0;t.files.forEach((s,o)=>{FT(s.path)||r(["files",o,"path"],"is not .skyramp/workspace.yml or a file under .skyramp/sut/"),n.has(s.path)&&r(["files",o,"path"],"file repeated"),n.add(s.path),MT.test(s.content)&&r(["files",o,"content"],"is not text");let a=Buffer.byteLength(s.content,"utf8");i+=a,a>Mf&&r(["files",o,"content"],`larger than ${Mf} bytes`)}),i>Ff&&r(["files"],`recipe text over ${Ff} bytes in total`)}),lot=y.object({schemaVersion:y.literal(1),stage:y.nativeEnum(Vz),event:y.nativeEnum(Wz),status:y.nativeEnum(Yz).optional()}).strict().refine(t=>t.status===void 0||t.event==="finished",{path:["status"],message:"only a finished stage has a status"}),Vw=100,Kye=5e3,Hz=2e3,zye=100,Zye=/^[A-Za-z0-9_-]{1,64}$/,uot=20,dot=200,Xye=100,pot=100,fot=200,hot=500,ej=/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/,mc=t=>y.string().max(t).refine(e=>e.trim().length>0&&!ej.test(e),"blank, or not text"),jw={sequence:y.number().int().min(1).max(Kye),at:y.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/)},eEe=y.discriminatedUnion("kind",[y.object({...jw,kind:y.literal("log"),phase:y.nativeEnum(VT),text:mc(Hz)}).strict(),y.object({...jw,kind:y.literal("component"),name:mc(zye),repository:mc(fot).refine(t=>/^[^/\s]+\/[^/\s]+$/.test(t),"not owner/name"),file:mc(hot).nullable(),status:y.nativeEnum(WT),version:mc(pot).optional()}).strict(),y.object({...jw,kind:y.literal("reply"),to:y.string().uuid(),accepted:y.boolean(),text:mc(Hz)}).strict(),y.object({...jw,kind:y.literal("question"),id:y.string().regex(Zye),type:y.nativeEnum(jT),text:mc(Hz),component:mc(zye).nullable(),choices:y.array(mc(dot)).max(uot),placeholder:mc(Xye).optional()}).strict(),y.object({...jw,kind:y.literal("delivered"),ids:y.array(y.string().uuid()).max(Vw)}).strict()]).superRefine((t,e)=>{t.kind==="question"&&(t.type==="free_text"!=(t.choices.length===0)&&e.addIssue({code:y.ZodIssueCode.custom,path:["choices"],message:"choices exactly when the question is not free_text"}),new Set(t.choices).size!==t.choices.length&&e.addIssue({code:y.ZodIssueCode.custom,path:["choices"],message:"a choice twice"}))}),mot=y.object({schemaVersion:y.literal(1),events:y.array(eEe).max(Vw)}).strict(),jye={id:y.string().uuid(),text:y.string(),by:y.string().nullable(),at:y.string()},got=y.discriminatedUnion("kind",[y.object({...jye,kind:y.literal("instruction"),question:y.null()}),y.object({...jye,kind:y.literal("answer"),question:y.string().regex(Zye)})]),Aot=y.object({schemaVersion:y.literal(1),leftOut:y.array(y.string()),messages:y.array(got).optional()}),yot=y.object({schemaVersion:y.literal(1),configuration:y.object({captureId:_l,revision:Ql.nullable(),hash:Xg}).strict(),capture:y.object({schemaVersion:y.literal(1),settings:y.object({target:y.object({environment:y.unknown()}).passthrough(),timeoutMinutes:y.number().int().positive()}).passthrough(),provenance:y.object({}).passthrough(),hash:Xg}).strict()}).strict(),Eot=$z.extend({version:y.number().int().positive(),components:y.array(y.object({name:y.string().min(1),repository:y.string().min(1)}).strict())}).strict(),bot=y.object({schemaVersion:y.literal(1),testEnvironment:Eot.nullable().optional(),runtimePlan:y.object({version:y.number().int().positive(),contentHash:Xg,files:y.array(y.object({path:y.string().refine(FT,"not a recipe file path"),content:y.string()}).strict()).min(1)}).strict().nullable()}).strict().refine(t=>!(t.runtimePlan&&t.testEnvironment),{message:"a run pins a recipe or a customer's Test Environment, never both",path:["testEnvironment"]}),wot=y.object({schemaVersion:y.literal(1),state:y.nativeEnum(Vye),ending:y.nativeEnum(HT).nullable(),cause:y.nativeEnum(zT).nullable(),deadlineAt:y.string().datetime()}).strict();function tEe(t){return t.reportUploaded?{schemaVersion:1,reason:"report_uploaded",cause:null}:t.recipeUploaded?{schemaVersion:1,reason:"recipe_uploaded",cause:null}:t.cancelled?{schemaVersion:1,reason:"cancelled",cause:null}:{schemaVersion:1,reason:"no_report",cause:Cot(t)}}function Cot(t){return t.credentialMissing?"credential_missing":t.checkoutFailed?"checkout_failed":t.setupFailed?"setup_failed":t.timedOut?"timed_out":"agent_failed"}var Iot=["generate-unit","native-run","finalize"],Sot=["preflight","plan","write",...Iot,"report","deliver"];var tA=(n=>(n.Unit="unit",n.Integration="integration",n.E2e="e2e",n))(tA||{});var YT=1440;dt();Pz();Of();var rEe;(function(t){t[t.lineFeed=10]="lineFeed",t[t.carriageReturn=13]="carriageReturn",t[t.space=32]="space",t[t._0=48]="_0",t[t._1=49]="_1",t[t._2=50]="_2",t[t._3=51]="_3",t[t._4=52]="_4",t[t._5=53]="_5",t[t._6=54]="_6",t[t._7=55]="_7",t[t._8=56]="_8",t[t._9=57]="_9",t[t.a=97]="a",t[t.b=98]="b",t[t.c=99]="c",t[t.d=100]="d",t[t.e=101]="e",t[t.f=102]="f",t[t.g=103]="g",t[t.h=104]="h",t[t.i=105]="i",t[t.j=106]="j",t[t.k=107]="k",t[t.l=108]="l",t[t.m=109]="m",t[t.n=110]="n",t[t.o=111]="o",t[t.p=112]="p",t[t.q=113]="q",t[t.r=114]="r",t[t.s=115]="s",t[t.t=116]="t",t[t.u=117]="u",t[t.v=118]="v",t[t.w=119]="w",t[t.x=120]="x",t[t.y=121]="y",t[t.z=122]="z",t[t.A=65]="A",t[t.B=66]="B",t[t.C=67]="C",t[t.D=68]="D",t[t.E=69]="E",t[t.F=70]="F",t[t.G=71]="G",t[t.H=72]="H",t[t.I=73]="I",t[t.J=74]="J",t[t.K=75]="K",t[t.L=76]="L",t[t.M=77]="M",t[t.N=78]="N",t[t.O=79]="O",t[t.P=80]="P",t[t.Q=81]="Q",t[t.R=82]="R",t[t.S=83]="S",t[t.T=84]="T",t[t.U=85]="U",t[t.V=86]="V",t[t.W=87]="W",t[t.X=88]="X",t[t.Y=89]="Y",t[t.Z=90]="Z",t[t.asterisk=42]="asterisk",t[t.backslash=92]="backslash",t[t.closeBrace=125]="closeBrace",t[t.closeBracket=93]="closeBracket",t[t.colon=58]="colon",t[t.comma=44]="comma",t[t.dot=46]="dot",t[t.doubleQuote=34]="doubleQuote",t[t.minus=45]="minus",t[t.openBrace=123]="openBrace",t[t.openBracket=91]="openBracket",t[t.plus=43]="plus",t[t.slash=47]="slash",t[t.formFeed=12]="formFeed",t[t.tab=9]="tab"})(rEe||(rEe={}));var vot=new Array(20).fill(0).map((t,e)=>" ".repeat(e)),rA=200,Bot={" ":{"\n":new Array(rA).fill(0).map((t,e)=>`
|
|
216
216
|
`+" ".repeat(e)),"\r":new Array(rA).fill(0).map((t,e)=>"\r"+" ".repeat(e)),"\r\n":new Array(rA).fill(0).map((t,e)=>`\r
|
|
217
217
|
`+" ".repeat(e))}," ":{"\n":new Array(rA).fill(0).map((t,e)=>`
|
|
218
218
|
`+" ".repeat(e)),"\r":new Array(rA).fill(0).map((t,e)=>"\r"+" ".repeat(e)),"\r\n":new Array(rA).fill(0).map((t,e)=>`\r
|
|
@@ -511,7 +511,7 @@ ${uft(t,e)}`}function uft(t,e){if(t.inputs.appRunning)return`${t.inputs.appRunni
|
|
|
511
511
|
`)[0].slice(0,600);A&&(c=`${p.slug}: ${w}`),a.push({schemaVersion:1,repository:p.slug,committed:!1,pushed:!1,prAction:"failed",prFailure:"unknown",prDetail:w,unstaged:[]})}}let l=bi.join(t.outputsDir,"pr-body.md"),u=bi.join(t.outputsDir,"deliver.json"),d={...a[0],deliveries:a};if(rh.writeFileSync(u,JSON.stringify(d,null,2)+`
|
|
512
512
|
`),c)throw new Error(`delivery failed in ${c}`);return{deliver:bi.relative(t.runDir,u),"pr-body":bi.relative(t.runDir,l)}}async function Fft(t,e,r,n,i,s){let o=n.path,c=ie(t,"finalize.json")?.commit?.message||r.commitMessage||"Skyramp Testbot: add tests",l=r.commitMessage||c,u=t.inputs.deliverRemote||"origin",d=s?s.headBranch||PSe(t.inputs.headBranch,t.inputs.baseBranch,o):PSe(void 0,void 0,o),p=Qft(d,t.inputs.deliverBranch),f=n.slug,A=QSe(Dft(r,t,n),{audience:"testbot-pr",requestedBy:t.inputs.requestedBy}),m=s?"pr-body.md":`pr-body-${OSe(f)}.md`,w=bi.join(t.outputsDir,m);rh.writeFileSync(w,A);let C=Ts(o,["rev-parse","HEAD"]);Ts(o,["checkout","-B",p]),Ts(o,["reset"]);let b=[];for(let F of i)try{Ts(o,["add","--",F])}catch{b.push(F)}let S=!1;try{Ts(o,["diff","--cached","--quiet"])}catch{Ts(o,["-c",`user.name=${Uw}`,"-c",`user.email=${Dz}`,"commit","-m",c]),S=!0}let x=Ts(o,["rev-parse","HEAD"]),Q,P=s?.headSha;if(S&&P&&P!==C)try{Ts(o,["checkout","-q","-B",p,P]),Ts(o,["-c",`user.name=${Uw}`,"-c",`user.email=${Dz}`,"cherry-pick","--keep-redundant-commits",x]),x=Ts(o,["rev-parse","HEAD"])}catch(F){try{Ts(o,["cherry-pick","--abort"])}catch{}Ts(o,["checkout","-q","-B",p,x]);let O=String(F.stderr??"").split(`
|
|
513
513
|
`).find(H=>H.trim())||(F instanceof Error?F.message.split(`
|
|
514
|
-
`)[0]:String(F));Q=`tests committed on the checkout's merge commit (re-cut onto ${P.slice(0,12)} failed: ${O.trim().slice(0,160)})`}let k=s?{}:{repositoryPath:o,repoSlug:f,devPr:null};if(!S){let F=await e.markTestsPrUnchanged({branch:p,...k});return{schemaVersion:1,repository:f,branch:p,remote:u,base:d,committed:!1,commitSha:x,pushed:!1,prAction:F.action==="unchanged"?"unchanged":"skipped",prUrl:F.url,prTitle:l,unstaged:b,reason:F.action==="unchanged"?"no test changes to commit \u2014 existing tests PR annotated as unchanged":"no test changes to commit \u2014 nothing pushed, no PR opened"}}let M=await e.publishTestsPr({repositoryPath:o,...k,remote:u,branch:p,base:d,commitSha:x,title:l,bodyFile:w,mode:t.inputs.deliverMode});return{schemaVersion:1,repository:f,branch:p,remote:u,base:M.base,requestedBase:d,committed:S,commitSha:x,pushed:M.pushed,...M.pushedCommits?{pushedCommits:M.pushedCommits}:{},prAction:M.action,...M.retargetedAs?{retargetedAs:M.retargetedAs}:{},prUrl:M.url,prTitle:l,...M.failure?{prFailure:M.failure,prDetail:M.detail}:{},...Q?{cutNote:Q}:{},...M.action==="skipped"&&M.detail?{reason:M.detail}:{},unstaged:b}}var sW={name:"deliver",timeoutMinutes:5,requires:["finalize","report"],validateInput:Nft,execute:Mft},Lft={...sW,requires:["report"],branchRequires:{runtime:["write"],"no-runtime":["finalize"]}};var ZKt={preflight:Dbe,onboard:ywe,analyze:Zbe,triage:SCe,deploy:fwe,recommend:vCe,generate:dIe,"generate-ui":fIe,"generate-unit":TV,"native-run":kV,adapt:QIe,finalize:jV,report:hSe,deliver:sW,plan:bSe,write:iW};var XKt="two-step",eZt=["two-step"];var tZt={preflight:"preflight",analyze:"plan",recommend:"plan",plan:"plan",deploy:"write",generate:"write","generate-ui":"write",adapt:"write",finalize:"write",write:"write",report:"report",deliver:"deliver",triage:"plan",onboard:"onboard","generate-unit":"generate-unit","native-run":"native-run"};var MSe=j(require("path"));var sZt=MSe.join(".skyramp","sut","get-auth-token.sh");var TZt=3*6e4;var kZt=`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;var Uft="https://testbot.skyramp.dev",qA={attemptId:"v3AttemptId",origin:"v3Origin",deadlineAt:"v3DeadlineAt",reportUploaded:"v3ReportUploaded",recipeUploaded:"v3RecipeUploaded",cause:"v3Cause"};var Gft=3e4;function qft(t){let e=t.ACTIONS_ID_TOKEN_REQUEST_URL,r=t.ACTIONS_ID_TOKEN_REQUEST_TOKEN;return delete t.ACTIONS_ID_TOKEN_REQUEST_URL,delete t.ACTIONS_ID_TOKEN_REQUEST_TOKEN,async n=>{if(!e||!r)throw new Error("The job cannot request an OIDC token. Give it the `id-token: write` permission.");let i=new URL(e);i.searchParams.set("audience",n);let s=await fetch(i,{headers:{Authorization:`Bearer ${r}`,Accept:"application/json"},redirect:"error",signal:AbortSignal.timeout(Gft)});if(!s.ok)throw new Error(`GitHub refused the OIDC token request: ${s.status}`);let o=(await s.json().catch(()=>({}))).value;if(typeof o!="string"||!o)throw new Error("GitHub's OIDC token response carried no token");return qs(o),o}}function $ft(t,e){return{origin:t,idToken:e,mask:r=>qs(r),log:r=>Re(r)}}var wXt={cancelled:"Skyramp cancelled this run",expired:"this attempt passed its deadline in Skyramp",ended:"Skyramp already ended this attempt"},CXt={cancelled:"cancelled",expired:"timed_out",ended:"agent_failed"};var IXt={analyze:"analyze",triage:"analyze",recommend:"recommend",generate:"generate","generate-ui":"generate","generate-unit":"generate",adapt:"generate",onboard:"execute",deploy:"execute","native-run":"execute",deliver:"deliver"},SXt={analyze:"change analysis",recommend:"test recommendations",generate:"test generation",execute:"test execution",deliver:"opening a pull request with the tests"};var xXt={onboard:"onboard",deploy:"deploy"};async function FSe(){let t=rs(qA.attemptId);if(!t)return;let e=rs(qA.reportUploaded)==="true",r=rs(qA.recipeUploaded)==="true",n=rs(qA.deadlineAt),i=rs(qA.cause)||void 0;!i&&!e&&!r&&n&&lEe(new Date(n),new Date)<=0&&(i="timed_out");let s=qft(process.env),o=await uEe({attemptId:t,reportUploaded:e,recipeUploaded:r,cause:i},$ft(rs(qA.origin)||Uft,s));Re(`Testbot V3: attempt ended; the run's outcome in Skyramp is ${o.outcome??"not final yet"}.`)}dt();var QN=j(require("crypto"));function oW(t){return Buffer.from(t).toString("base64url")}function Hft(t){return t.replace(/\\r\\n/g,`
|
|
514
|
+
`)[0]:String(F));Q=`tests committed on the checkout's merge commit (re-cut onto ${P.slice(0,12)} failed: ${O.trim().slice(0,160)})`}let k=s?{}:{repositoryPath:o,repoSlug:f,devPr:null};if(!S){let F=await e.markTestsPrUnchanged({branch:p,...k});return{schemaVersion:1,repository:f,branch:p,remote:u,base:d,committed:!1,commitSha:x,pushed:!1,prAction:F.action==="unchanged"?"unchanged":"skipped",prUrl:F.url,prTitle:l,unstaged:b,reason:F.action==="unchanged"?"no test changes to commit \u2014 existing tests PR annotated as unchanged":"no test changes to commit \u2014 nothing pushed, no PR opened"}}let M=await e.publishTestsPr({repositoryPath:o,...k,remote:u,branch:p,base:d,commitSha:x,title:l,bodyFile:w,mode:t.inputs.deliverMode});return{schemaVersion:1,repository:f,branch:p,remote:u,base:M.base,requestedBase:d,committed:S,commitSha:x,pushed:M.pushed,...M.pushedCommits?{pushedCommits:M.pushedCommits}:{},prAction:M.action,...M.retargetedAs?{retargetedAs:M.retargetedAs}:{},prUrl:M.url,prTitle:l,...M.failure?{prFailure:M.failure,prDetail:M.detail}:{},...Q?{cutNote:Q}:{},...M.action==="skipped"&&M.detail?{reason:M.detail}:{},unstaged:b}}var sW={name:"deliver",timeoutMinutes:5,requires:["finalize","report"],validateInput:Nft,execute:Mft},Lft={...sW,requires:["report"],branchRequires:{runtime:["write"],"no-runtime":["finalize"]}};var ZKt={preflight:Dbe,onboard:ywe,analyze:Zbe,triage:SCe,deploy:fwe,recommend:vCe,generate:dIe,"generate-ui":fIe,"generate-unit":TV,"native-run":kV,adapt:QIe,finalize:jV,report:hSe,deliver:sW,plan:bSe,write:iW};var XKt="two-step",eZt=["two-step"];var tZt={preflight:"preflight",analyze:"plan",recommend:"plan",plan:"plan",deploy:"write",generate:"write","generate-ui":"write",adapt:"write",finalize:"write",write:"write",report:"report",deliver:"deliver",triage:"plan",onboard:"onboard","generate-unit":"generate-unit","native-run":"native-run"};var MSe=j(require("path"));var sZt=MSe.join(".skyramp","sut","get-auth-token.sh");var TZt=3*6e4;var kZt=`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;var Uft="https://testbot.skyramp.dev",qA={attemptId:"v3AttemptId",origin:"v3Origin",deadlineAt:"v3DeadlineAt",reportUploaded:"v3ReportUploaded",recipeUploaded:"v3RecipeUploaded",cause:"v3Cause"};var Gft=3e4;function qft(t){let e=t.ACTIONS_ID_TOKEN_REQUEST_URL,r=t.ACTIONS_ID_TOKEN_REQUEST_TOKEN;return delete t.ACTIONS_ID_TOKEN_REQUEST_URL,delete t.ACTIONS_ID_TOKEN_REQUEST_TOKEN,async n=>{if(!e||!r)throw new Error("The job cannot request an OIDC token. Give it the `id-token: write` permission.");let i=new URL(e);i.searchParams.set("audience",n);let s=await fetch(i,{headers:{Authorization:`Bearer ${r}`,Accept:"application/json"},redirect:"error",signal:AbortSignal.timeout(Gft)});if(!s.ok)throw new Error(`GitHub refused the OIDC token request: ${s.status}`);let o=(await s.json().catch(()=>({}))).value;if(typeof o!="string"||!o)throw new Error("GitHub's OIDC token response carried no token");return qs(o),o}}function $ft(t,e){return{origin:t,idToken:e,mask:r=>qs(r),log:r=>Re(r)}}var wXt={cancelled:"Skyramp cancelled this run",expired:"this attempt passed its deadline in Skyramp",ended:"Skyramp already ended this attempt"},CXt={cancelled:"cancelled",expired:"timed_out",ended:"agent_failed"};var IXt={analyze:"analyze",triage:"analyze",recommend:"recommend",generate:"generate","generate-ui":"generate","generate-unit":"generate",adapt:"generate",write:"generate",onboard:"execute",deploy:"execute","native-run":"execute",deliver:"deliver"},SXt={analyze:"change analysis",recommend:"test recommendations",generate:"test generation",execute:"test execution",deliver:"opening a pull request with the tests"};var xXt={onboard:"onboard",deploy:"deploy"};async function FSe(){let t=rs(qA.attemptId);if(!t)return;let e=rs(qA.reportUploaded)==="true",r=rs(qA.recipeUploaded)==="true",n=rs(qA.deadlineAt),i=rs(qA.cause)||void 0;!i&&!e&&!r&&n&&lEe(new Date(n),new Date)<=0&&(i="timed_out");let s=qft(process.env),o=await uEe({attemptId:t,reportUploaded:e,recipeUploaded:r,cause:i},$ft(rs(qA.origin)||Uft,s));Re(`Testbot V3: attempt ended; the run's outcome in Skyramp is ${o.outcome??"not final yet"}.`)}dt();var QN=j(require("crypto"));function oW(t){return Buffer.from(t).toString("base64url")}function Hft(t){return t.replace(/\\r\\n/g,`
|
|
515
515
|
`).replace(/\\n/g,`
|
|
516
516
|
`).trim()}function zft(t){return t.includes("-----BEGIN RSA PRIVATE KEY-----")}function jft(t){return t.includes("-----BEGIN OPENSSH PRIVATE KEY-----")}function Vft(t){let e=t.split(`
|
|
517
517
|
`).map(r=>r.trim()).filter(r=>r&&!r.startsWith("-----")).join("");return Buffer.from(e,"base64")}function Wft(t){let e=Hft(t);if(jft(e))throw new Error(`githubAppPrivateKey is in OpenSSH format, but GitHub Apps issue PKCS#1 ("-----BEGIN RSA PRIVATE KEY-----") or PKCS#8 ("-----BEGIN PRIVATE KEY-----") keys. Re-download the .pem from the GitHub App's settings page.`);let r=zft(e)?"pkcs1":"pkcs8";try{return QN.createPrivateKey({key:Vft(e),format:"der",type:r})}catch(n){let i=r==="pkcs1"?"PKCS#1":"PKCS#8";throw new Error(`Failed to parse githubAppPrivateKey as a ${i} private key: ${n instanceof Error?n.message:String(n)}. Ensure the secret contains the full PEM, unmodified from the GitHub App's downloaded .pem file.`)}}function Yft(t,e,r=Date.now()){let n=Math.floor(r/1e3),i=oW(JSON.stringify({alg:"RS256",typ:"JWT"})),s=oW(JSON.stringify({iat:n-60,exp:n+540,iss:t})),o=`${i}.${s}`,a=Wft(e),c=QN.createSign("RSA-SHA256").update(o).sign(a);return`${o}.${oW(c)}`}var Jft=50,_N=class{opts;now;fetchImpl;repositories;installationId;cached;inFlight;scopeGeneration=0;constructor(e){this.opts=e,this.now=e.now??Date.now,this.fetchImpl=e.fetchImpl??fetch,this.repositories=e.repositories}setRepositories(e){this.repositories=e,this.scopeGeneration++,this.cached=void 0,this.inFlight=void 0}async getToken(){if(this.cached&&this.now()-this.cached.mintedAtMs<this.refreshThresholdMs())return this.cached.token;if(!this.inFlight){let e=this.mint().finally(()=>{this.inFlight===e&&(this.inFlight=void 0)});this.inFlight=e}return this.inFlight}refreshThresholdMs(){let e=process.env.SKYRAMP_TOKEN_REFRESH_THRESHOLD_MINUTES;return e!==void 0&&e!==""&&!isNaN(Number(e))?Number(e)*6e4:this.opts.refreshThresholdMs??Jft*6e4}async mint(){let e=this.scopeGeneration,r=this.now(),n=Yft(this.opts.appId,this.opts.privateKey,r),i=await this.discoverInstallationId(n),s=await this.request("POST",`/app/installations/${i}/access_tokens`,n,{repositories:this.repositories});return qs(s.token),e===this.scopeGeneration&&(this.cached={token:s.token,mintedAtMs:r}),s.token}async discoverInstallationId(e){if(this.installationId===void 0){let r=await this.request("GET",`/repos/${this.opts.owner}/${this.opts.repo}/installation`,e);this.installationId=r.id}return this.installationId}async request(e,r,n,i){let s=process.env.GITHUB_API_URL??"https://api.github.com",o=await this.fetchImpl(`${s}${r}`,{method:e,headers:{authorization:`Bearer ${n}`,accept:"application/vnd.github+json","user-agent":"skyramp-testbot",...i!==void 0&&{"content-type":"application/json"}},body:i===void 0?void 0:JSON.stringify(i)});if(!o.ok){let a=await o.text().catch(()=>"");throw new Error(`GitHub App installation token request failed: ${e} ${r} returned ${o.status}. Check githubAppId/githubAppPrivateKey and that the App is installed on `+`${this.opts.owner}/${this.opts.repo}. ${a}`.trim())}return o.json()}};Of();async function LSe(){xge(ET(Oe("language")));try{await FSe()}catch(n){Me(`Testbot V3: could not end the attempt: ${n instanceof Error?n.message:String(n)}`)}try{let n=Oz(),i=($A.existsSync(n)?$A.readdirSync(n):[]).filter(f=>/^agent-log\.attempt-\d+\.ndjson$/.test(f)).sort((f,A)=>f.localeCompare(A,void 0,{numeric:!0})).map(f=>Vl.join(n,f)),s=Vl.join(n,Mz),o=[...i,...$A.existsSync(s)?[s]:[]],a=Vl.join(n,"testbot-result.txt"),c=Vl.join(n,"combined-result.txt"),l=Vl.join(n,"agent-stdout.txt"),u=Vl.join(n,Dye),d=new Lg;o.length>0&&await d.uploadArtifact("skyramp-agent-logs",o,n);let p=[a,c,l,u].filter(f=>$A.existsSync(f));p.length>0&&await d.uploadArtifact("skyramp-testbot-report",p,n)}catch(n){Me(`Failed to upload artifacts in post step: ${n instanceof Error?n.message:String(n)}`)}try{let n=_ge(),i=await Cye(n),s=Vl.resolve(n.workingDirectory);await Bye(i,s)}catch(n){Me(`Service teardown error: ${n instanceof Error?n.message:String(n)}`)}let t=rs("progressCommentId"),e=rs("completed"),r=rs("cancelled")==="true";if(t&&!e&&r)try{let n=Oe("githubToken"),i=Oe("githubAppId"),s=Oe("githubAppPrivateKey");delete process.env.INPUT_GITHUBAPPPRIVATEKEY;let o=n;if(i&&s){let f=Qz(process.env.GITHUB_REPOSITORY??"");if(f){let A=new _N({appId:i,privateKey:s,owner:f.owner,repo:f.repo,repositories:[f.repo]});o=()=>A.getToken()}}if(!o)return;let a=Fz(o);Rye(a);let c=parseInt(t,10),l=rs("steps"),u=l?JSON.parse(l):[],d=a.getRunUrl(),p=Tye(u,d);await a.updateComment({id:c},p),Do("Progress comment updated with cancellation notice")}catch(n){Me(`Failed to update progress comment on cancellation: ${n}`)}}process.env.NODE_ENV!=="test"&&(Qge(),LSe().catch(t=>{RD(t instanceof Error?t.message:String(t))}));0&&(module.exports={post});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyramp/testbot-core",
|
|
3
|
-
"version": "0.13.0-v3.
|
|
3
|
+
"version": "0.13.0-v3.61",
|
|
4
4
|
"description": "Skyramp Testbot engine: AI-powered deterministic test generation, execution and maintenance",
|
|
5
5
|
"main": "dist/main.js",
|
|
6
6
|
"//files": "An explicit allowlist, never a glob. `dist/` is gitignored, so without this key npm's .gitignore fallback would publish a package with no engine in it; with a glob it would publish the sourcemaps, whose sourcesContent embeds every src/*.ts verbatim. eval-entry.js is a development entry and must not ship. dist/VERSION.json exists only in a release-engine.yml build. assets/gen-reference/ is the staged codegen reference corpus, which generate.ts finds at ../assets from dist/.",
|