diff --git a/AGENTS.md b/AGENTS.md index e1b665e0..a0212ded 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,20 +1,26 @@ # authority — agent instructions This repo is the **host authority interface** and its development implementation, -the **authority gateway**. One sentence of responsibility: declare what a module or +the **local authority**. One sentence of responsibility: declare what a module or solution calls on its host to be issued and checked authority, and provide the one small process that implements it on a laptop. If a change makes that sentence need another clause, it does not belong here. -- **Owns:** the interface declaration; the authority gateway service; later, the +- **Owns:** the interface declaration; the local authority service; later, the authority proto, verifier and conformance kit moved from core. - **Never contains:** a second implementation of sign-in, minting or grant - derivation (the authority gateway links the host's packages); a store the host does + derivation (the local authority links the host's packages); a store the host does not also use; any solution, customer or business-line name; a route of the product frontend; anything the CLI should do (rendering, per-process launcher credentials). -- **Depends on:** the host's authority packages (codefly-dev/module-saas-starter) - and core's Work Context types until step 3 moves them here. +- **Depends on today:** Core's Work Context authority/verifier, workload + attestation and composition packages, plus this repo's libraries. The local + service does not currently import module-saas-starter. + +The host-package reuse requirement above is an unresolved design obligation: +the existing local issuer/state resolves fixture grants itself. Do not add a +parallel resolver, infer that local tests prove SaaS parity, or silently erase +that obligation to match the implementation. Reconcile it with the host owner. Rules, governed by https://github.com/obin-ai/handbook/blob/main/concepts/boundaries.md and the development contract at diff --git a/README.md b/README.md index f36cf3c6..27dbf364 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # authority **What we are doing.** Making the interface the mapping between local development -and deployment. The small gateway a developer runs on a laptop and the host's +and deployment. The local authority a developer runs on a laptop and the host's accounts service implement the same declared contract, checked by the render and proven by one suite, so what passes on the laptop is what runs on the cell and what refuses on the laptop is what refuses on the cell. Without the interface @@ -13,21 +13,23 @@ This repository holds two things, and only these two: a Codefly interface declaring what a module or solution calls on the host that runs it. Issue a Work Context for a person, an installation or a module's own binding; re-address, derive a child, renew; check a revision live; the current - installation. The host's `accounts` service implements it in full. A module + installation. The host's `accounts` service implements the same interface; + provider qualification gaps are recorded below. A module depends on the interface, never on a service. -2. **The authority gateway** (`modules/authority/services/gateway`): the development +2. **The local authority** (`modules/authority/services/local`): the development implementation. One process that signs in fixture people with their roles, issues and verifies Work Contexts, knows the composition from the rendered manifests, and holds the fixture installations in memory. No accounts service, no stores, no platform frontend. Running a solution locally is the solution, the modules it consumes, and this. -**What keeps the authority gateway from being a second authority.** It links the same -packages `accounts` uses to sign in, mint and derive a module's grant from its -manifest, and the conformance kit runs against both implementations in one test. -It is a profile of the host, not a reimplementation. If a package of `accounts` -cannot be linked without its store, the package is split in the host; nothing is -copied here. +**What is reused today.** The local implementation uses Core's Work Context +authority/verifier, workload attestation and signed composition machinery. +Its issuer/state resolves fixture grants; it does not currently link Accounts' +sign-in or grant-derivation packages. The original host-package reuse requirement +remains an unresolved design obligation with the host owner, not a guarantee +established by this checkout. The shared conformance suite must run against both +implementations; a local pass or a skipped provider scenario does not prove parity. **What this repo is, in one line.** The interfaces the host's saas component MUST satisfy, with the suite that proves it, and the development implementation @@ -36,8 +38,8 @@ that satisfies them on a laptop, fixture included. **Order of work.** 1. Declare the interfaces and give them their protos, reduced to the six duties - (done; `interfaces/`, `modules/authority/services/gateway/proto/host/*/v1`). -2. Build the authority gateway against them with the suite every implementation must + (done; `interfaces/`, `modules/authority/services/local/proto/host/*/v1`). +2. Build the local authority against them with the suite every implementation must pass (done; `pkg/conformance`, run over gRPC in `plugins/registry_test`). 3. Point the host and the SDKs at these packages; run `pkg/conformance` against accounts; delete the copies in `codefly-dev/core` and the host, fixtures proving @@ -57,7 +59,9 @@ runtime, records and the org-directory page. to documents at Acme, write refused by name. 4 documents embeds through model for itself under its binding; `modelservice` is refused as not composed; the second binding the envelope forgot this week is simply there. 5 A 60-second - child for the runtime, actor documents, nothing widened. 6 The wiki reconciles + child for Runtime is refused for Maya, who has no Runtime grant; the entitled + developer succeeds with actor documents and only the Runtime binding's scopes. + 6 The wiki reconciles overnight as its installation; uninstalled at 10:00, its 09:58 token is refused. 7 Maya opens the directory page and is issued records read; Rémi gets write; the UI follows the token. 8 All of it ran with no accounts service, no store, no @@ -91,7 +95,7 @@ template always returns nil, so `plugins/plugins.yaml` is declared but not rendered; the four plugins implement the agent's own `framework.Plugin` and are wired in the tests, and serving them from the agent's server is the agent's work, not a hand edit of `registry_gen.go`. `codefly generate client --from -authority/gateway/grpc --language go,python` writes two Go packages (`api` from +authority/local/grpc --language go,python` writes two Go packages (`api` from the scaffold's proto, `authority` from ours) into one facade directory and fails its own build; the Go and Python clients that would replace the solution SDK wait on that fix. @@ -99,7 +103,7 @@ on that fix. **Where the thinking is.** The Platform Authority Primer (decisions 6 and 7) and the handbook proposal that will carry them. Run it with `codefly run` from the module. -## What the authority gateway must serve, read from the callers (2026-10-21) +## What the local authority must serve, read from the callers (2026-10-21) Inventory taken from the code that calls the host today: the module SDK (`saas-sdk-go/moduleauthority`), the solution runtime (`solution-runtime-go`), the @@ -114,7 +118,7 @@ design. | A fixture person signs in | `POST /v1/auth/authenticate` with `fixture_token` (accounts `auth/dev` validator); `/v1/auth/refresh` | | Verify what the host issued | `GET /v1/auth/.well-known/jwks.json` (also `/jwks`, `/.well-known/openid-configuration`) | | The composition reaches the host | `POST /platform/_delivery/manifest` (one signed manifest per module instance) | -| What a module may hold | derived from the manifest; today `GET`/`PUT /v1/platform/module-envelope`, which the authority gateway does not serve | +| What a module may hold | derived from the manifest; today `GET`/`PUT /v1/platform/module-envelope`, which the local authority does not serve | | The module's workload becomes a principal and gets Work Contexts | gateway workload endpoint: `POST /modules/_work-context` (for a person), `/modules/_operation-context` (the module's own binding), `/modules/_source-operation-context` (a source delegation) | | The module calls the host as itself | Connect proxy at `/modules/_authority` → `ModuleCapabilitiesService`: `ExchangeDelegatedOperationAudience`, `EmitAuditEvent`, `DeclareAuditEventTypes`, `AuthorizeExecutableArtifact` / `ApproveExecutableArtifact`, `NotifyUser` / `NotifyOrgAdmins` | | Person-owned authority | `WorkContextService`: `StartTask`, `ExchangeAudience`, `StartChildSession`, `RenewWorkContext`, `CheckAuthorizationRevision`, `StartInstallationTask`, `AuthorizeEvidenceRead`, `ConsumeSingleUse` | @@ -171,7 +175,7 @@ talks to. Against that: **What remains is the interface.** Authority: `Issue`, `Check`, `Keys`. Composition: `ApplyManifest`. Installation: `Install`, `GrantToTeam`, `List`, and the install step callback. Sign-in at the browser edge only. Routing is the data -plane, not a contract. 0.1.0 mirrors today's spellings so the authority gateway serves +plane, not a contract. 0.1.0 mirrors today's spellings so the local authority serves the SDKs as they are; the reduced shape is 0.2.0, a host contract change through a handbook proposal, after which the SDKs move once. @@ -206,10 +210,10 @@ Each rung proves one claim; nothing is deleted before the rung above it is green | Rung | Claim | How | Pass | Owner | |---|---|---|---|---| -| 0 | the authority gateway holds | 47 tests here: byte identity, core's kit, scenario, `pkg/conformance` over gRPC | green (done) | this repo | +| 0 | the local authority holds | 47 tests here: byte identity, core's kit, scenario, `pkg/conformance` over gRPC | green (done) | this repo | | 1 | one contract, two implementations | accounts implements the four interfaces as adapters over what it does; saas CI runs `pkg/conformance` against it with the saas fixture | same codes, same reasons on both | module-saas-starter | -| 2 | a module cannot tell which answered | documents takes the generated authority client and requires the interface, not a service; runs against the authority gateway and against accounts | identical tests, playground and refusals; the render picks the implementation | module-document-store, saas-sdk-go | -| 3 | a solution needs no runtime | the wiki as an agent-scaffolded service on the generated clients; wiki + documents + authority gateway, then the full host locally, then obin-staging; the eight steps through the UI | the scenario passes end to end; no envelope, anchor or audience key anywhere | core-solutions | +| 2 | a module cannot tell which answered | documents takes the generated authority client and requires the interface, not a service; runs against the local authority and against accounts | identical tests, playground and refusals; the render picks the implementation | module-document-store, saas-sdk-go | +| 3 | a solution needs no runtime | the wiki as an agent-scaffolded service on the generated clients; wiki + documents + local authority, then the full host locally, then obin-staging; the eight steps through the UI | the scenario passes end to end; no envelope, anchor or audience key anywhere | core-solutions | | 4 | the laptop refuses where the cell refuses | recorded request vectors replayed against both, compared field by field; property tests on the four ways a token widens; replay, expiry, revocation, forgery; one independent security review | zero divergence, zero widening, findings closed | this repo + reviewer | | 5 | it is fast | clean clone → Maya sees the wiki, one command, timed; a grep gate against envelope files and audience keys | the owner's number; gate green fleet-wide | cli, handbook | @@ -220,8 +224,8 @@ staging validated. **Rung 1 first; it is the one that matters (owner, 2026-10-21).** The loop: 1. Cut a branch in module-saas-starter. accounts declares in its module - interface that it implements `codefly.dev/authority@0.1.0`, `codefly.dev/composition@0.1.0`, - `codefly.dev/installation@0.1.0` and `codefly.dev/session@0.1.0`, takes this repo's + interface that it implements `codefly.dev/authority@0.2.0`, `codefly.dev/composition@0.1.0`, + `codefly.dev/installation@0.1.0` and `codefly.dev/session@0.2.0`, takes this repo's protos (bindings via `codefly generate proto`), and serves the four services as adapters over what it already has: `Issue` → StartTask / StartInstallationTask / the module broker's mint / StartChildSession-ExchangeAudience-Renew by owner @@ -262,12 +266,12 @@ not run yet, because of what the branch found: Gap 7 was a decision, taken on 2026-10-22: the interface carries the host's names, see "The namespace, settled" below. Gaps 1 and 2 closed the same day on the host branch; a ninth surfaced and closed with them: the generated service catalog crossed the host's naming-gate scan cap (512 KiB) at 40 services, and the gate now skips that generated file for the reason it skips descriptors. -**What the second implementation taught the interface.** `GrantToTeamRequest` gained `organization_id`: the host checks an administrator against the organisation before it reads the installation, so the request must name it; the authority gateway now refuses a grant naming another organisation than the installation's, and the suite asserts it. That is what a second implementation is for. +**What the second implementation taught the interface.** `GrantToTeamRequest` gained `organization_id`: the host checks an administrator against the organisation before it reads the installation, so the request must name it; the local authority now refuses a grant naming another organisation than the installation's, and the suite asserts it. That is what a second implementation is for. ## The namespace, settled (2026-10-22) The interfaces are the host's contract, so they carry the host's names: publisher -`codefly.dev` (ids `codefly.dev/authority@0.1.0`, `composition`, `installation`, +`codefly.dev` (ids `codefly.dev/authority@0.2.0`, `composition`, `installation`, `installable`, `session`) and protobuf packages `host.authority.v1`, `host.composition.v1`, `host.installation.v1`, `host.session.v1` under `proto/host/`. Not `codefly.*`: the host's buf configuration excludes a `codefly/` proto directory @@ -280,7 +284,7 @@ scans files, not URLs. This closes gap 7 of rung 1. **Invariant:** one declared interface and one suite on both sides from phase 0 on, so local development to deployment is correct by construction. Phases: 0 now -(interfaces, authority gateway, host adapters on a branch; protos and policy exist +(interfaces, local authority, host adapters on a branch; protos and policy exist twice, knowingly); 1 rung 1 done (suite green against accounts, refusing adapters made real, suite and credential and person shape corrected, digest check on the copied protos); 2 the wiki against the branch; 3 rungs 2 and 3 (agent and CLI @@ -292,7 +296,7 @@ Deletions only in 4 and 5, each behind a green suite and staging. The full table is the handbook's `design/host-authority-interface.md`. **Corrections of 2026-10-22 (`0403966`).** The suite accepts pending or active from -Install. The authority gateway attests core's native launcher credential against the +Install. The local authority attests core's native launcher credential against the launcher's anchor; nothing of its own. The person shape is the caller's bearer; `PersonSession` is empty. See the handbook's audit sidecar for the reasoning. @@ -304,8 +308,24 @@ consumer's organisation in an import path). GitHub redirects the old location. `libraries/authority-client/go` is the generated Go bindings library (`codefly generate client --no-facade`), importable as `github.com/codefly-dev/authority/libraries/authority-client/go`. The Python -library did not generate: the client generator lacks the protovalidate dependency -the Work Context messages import (reported on codefly-dev/cli#1107). +library publishes generated bindings under `libraries/authority-client/python`. +The [Python bound-context reader](libraries/authority-client/python/README.md) projects +effective resource scopes without another verification call. Consumers read the +hop stamp first and retain their domain resource and installation checks. +The [Go reader](libraries/authority-client/go/README.md) reuses Core Decode and +scope containment; the [TypeScript reader](libraries/authority-client/typescript/README.md) +uses Codefly-generated protobuf bindings. Shared Core-produced fixtures cover +their scope decisions. These projections do not authenticate a context or replace +live checks; TypeScript hop-binding integration remains separate work. Go also +retains Core's stronger structural validation. + +After changing local Go library dependencies, validate all four services as +standalone modules: local, hop, edge and console API. The latter three consume +the local authority client; local has other local library replacements. Run +`GOWORK=off go mod tidy -diff`, `GOWORK=off go test -race ./...` and +`GOWORK=off go vet ./...` from each service's `code/` directory. Workspace-only +library tests can hide stale service module graphs and leave `codefly run` +unable to build. ## Rules of change (owner, 2026-10-22) @@ -323,8 +343,10 @@ the Work Context messages import (reported on codefly-dev/cli#1107). ## Roles and the permission matrix -A solution declares its roles in its manifest, each within what the solution -serves, and one of them is `installer`: whoever installs the solution holds it on +A solution declares its roles in its canonical `module.contract.codefly.yaml`, +each within what the solution serves or explicitly consumes through its invoke +and lookup bindings. Headless-only permissions cannot supply a role grant. +One role is `installer`: whoever installs the solution holds it on that installation, which is the install-and-configure surface. A module declares no roles; a person's access to a module is the organisation's roles intersected with what the module serves. A person's access to a solution is the role its @@ -333,40 +355,142 @@ role through a granted team, and nothing from the organisation's roles. Another organisation's installation grants nothing. The values of real roles belong to each solution's manifest and arrive through the carrier: core's manifest carries no roles, so they travel in the authority's own document delivered with it -(`AuthorityManifestV1.roles`, as the sketch's `ModuleManifestV1.roles`), each -within the solution's scope ceilings in the same document. This repository holds +(`AuthorityManifestV1.roles`, as the sketch's `ModuleManifestV1.roles`), bounded +by the solution's own scope ceilings and the invoke/lookup scopes in the paired +Core manifest. Consumed kinds do not become kinds the solution serves. This repository holds the contract and its evaluation, never a product's roles. +An installation acting for itself resolves its selected role in that installed +solution's manifest, using the same role source as installation validation. +An organisation role with the same label supplies no authority to it. The +requested audience still intersects that role with what it serves; a binding +alone does not grant downstream module access. A role may explicitly grant a +consumed permission within those bindings, allowing the installation's agent to +issue at that module or carry it on a child call. Resource restrictions survive +that intersection. + +For person-owned work through a solution, the person's effective installation +roles are the permission source, including explicitly declared consumed grants. +No additional organisation grant is required. Installer-only owners hold only the +installer role; members of granted teams hold the selected role; a person in both +positions holds their union. A binding is a ceiling, never an independent grant. +The authority applies this source to person issuance naming a solution binding, +children, delegation admission and use, and resource reads. Every solution in the +verified actor chain continues to bound later module calls; a later module cannot +recover a permission that the solution role withheld. A target solution also +requires the person's entitlement there. Independent person-to-module work still +uses organisation roles; child derivation follows the target rule below. + +Solution roles preserve exact resource IDs and whole-kind grants through issuance +and resource listing. Restricted grants still do not satisfy a method policy +requiring a whole kind. Solutions must declare their intended consumed permissions +in their own roles; missing declarations cause refusal, not an organisation-role +fallback. Tests cover both denied organisation rights and permitted solution rights, +signed role delivery, multiple solution actors, and role/installation/delegation +revocation. SaaS parity and composed browser qualification remain separate work. +Installation-owned calls to another solution still need the target-consent contract +tracked by the pending tool-matrix row 11; this person rule does not supply it. + +Delivering a narrower or removed selected role, or narrowing the installer's +role, advances active installation seals and the affected organisations' +authorization revisions. Existing roots and descendants are then refused by +Core's ordinary live verification. Role expansion alone leaves existing narrow +installation roots valid; module actors still obey their generation checks. +New issuance resolves the current declaration. + +Issuance binds those role reads to the authorization revision Core signs. If +delivery changes it between resolution and minting, issuance refuses with +`permissions changed during issuance`; it does not retry with the old scopes. +Workload, delegated and child binding resolution likewise must match the signed +binding's module generation. Narrowing, removing or retargeting a binding also +advances the active installations' seals and organization revisions: person +roots can carry its scopes for a later hop without carrying the module's epoch. +Organization revision invalidation is coarse: unrelated existing capabilities in +each affected organization also need fresh issuance. Current grants remain usable. +A change after version capture leaves an older capability that ordinary +verification refuses. Deterministic issuer tests cover +role narrowing/removal and binding narrowing/removal before resolution, during +minting and after issuance. These checks do not choose a child-scope policy or +qualify the separate accounts implementation. + +Installation administration (`List`, `Install`, `GrantToTeam`) requires an open +session whose current person is an administrator or owner of the requested +organization. Anonymous and invalid sessions are `Unauthenticated`; a member or +an administrator of another organization receives `PermissionDenied`. This is +not the navigation API: a member probes each target with an empty-scope `Issue`. +That call returns `FailedPrecondition` when the audience has no active +installation in the person's organization, and `PermissionDenied` when installed +but the person holds no grant. Shared conformance exercises both distinctions; +its optional `UnentitledToken` must name a fixture person with no roles or teams. +The local fixture includes `no-roles` in Acme for that case. + The suite proves it as a matrix: the fixture states, for each person at each audience, which kind and action is allowed and which refused, and the suite asks -for exactly that scope and expects the answer. The authority gateway's fixture carries -two organisations, five people, three organisation roles, one solution with three -roles installed twice, and 25 cells. The host supplies its own matrix from its +for exactly that scope and expects the answer. The local authority's fixture carries +two organisations, a person with no roles or teams, an automatically generated +developer role, and a solution installed under different roles. The host supplies its own matrix from its own fixture. When the fixture signs, the suite composes its solution as a carrier with the authority's document carrying its roles; the sketch remains for a fixture that does not sign. +The local authority also logs a delivery-time role × method report and +generates its local developer role from concrete delivered permissions. See +[local permission diagnostics](modules/authority/services/local/README.md#permission-diagnostics-during-local-development) +for the distinction between static coverage and runtime authorization. + ## Delegate chains: a module inherits who it acts for -Owner's rule of 2026-10-23, generic to every module that acts for someone (robin +Owner's rule A of 2026-10-25, generic to every module that acts for someone (robin and runtime first): a module holds no standing authority over anyone's data. Its hop on a person's or an installation's token is owned by that principal, adds -the module to the actor chain, and has as its ceiling the owner's authority twice -over: what was already delegated down the chain (the parent's scopes) and what -the owner holds now at the hop's audience through the module's binding. An ask -narrows the ceiling; the child never outlives its parent. A module hops only on a +the module to the actor chain, and derives its scopes for each target from the +owner's current grants intersected with the selected binding, capped by the +parent's per-kind limits. Dropped actions and restricted resource IDs stay +restricted even after an intermediate call to another audience. An explicit ask +that drops an entire current-target kind leaves a zero-action cap; disjoint +resource sets also leave that cap, never an unrestricted empty resource list. +A kind never visited can still be derived from the owner's current grants. + +Authority scopes and replayed prior actors carry those limits across audiences; +the final actor receives only the current target's effective scopes. Carried +limits are not usable authority at that target. A service-owned context has no +person role to recover and retains only its existing authority through the +binding. A stored `Delegate` grant remains a complete ceiling: absent kinds, +dropped actions and named resource IDs cannot return. Every matching stored +delegation must still authorize the owner and actor. The target projection does +not replace that durable grant. +The child never outlives its parent. A module hops only on a token addressed to it and names the binding it exercises. Revoking the person's access, or changing the solution's role, revokes every delegate on the next call. The suite proves it with a chain of three modules where the last hop gets a read the person's first token never carried. +The shared `conformance.Fixture.ChildScopes` case proves exact effective target +scopes, exclusion of unrelated carried caps, a two-target stored delegation, +resource discovery, refusal to restore actions/IDs, and descendant revocation. +Each host must populate this fixture: an omitted case fails conformance. +`Fixture.ParentLimits` additionally proves action, resource and entirely dropped +kind restrictions across repeated audience round trips. Local issuer tests cover +disjoint target actions/IDs, service-owned attenuation, and revocation +interleavings. A missing, undeclared or misaddressed binding is refused before +verification can spend a single-use parent; binding seals use +`//`. SaaS must run this same +suite against its own real adapters before cross-host qualification is claimed. + ## The hop: one door in front of a module (2026-10-23) The hop is the authority module's second service. It stands in front of a module and lets through only a call the authority checked. For each call it reads the caller's Work Context, asks the interface's `Check` with the module's principal as the audience, removes any stamp the caller sent, writes its own stamp, and -forwards the call as opaque frames. It knows no method of the module. +forwards the call as opaque frames. Its generated catalog snapshot identifies +each method's service and endpoint; it does not interpret permission requirements. +See [hop routing and upgrade requirements](modules/authority/services/hop/README.md). + +The hop always listens on its declared HTTP endpoint, including in a +gRPC-only composition. An empty HTTP routing table does not remove that +endpoint from Codefly's readiness checks. Requests still pass through the +authority decision and are refused when no corresponding HTTP upstream exists. The module behind it carries one interceptor from `libraries/hop/go` and no other authority code. The stamp binds the digest of the Work Context the hop @@ -377,6 +501,16 @@ token and asks no authority. The stamp is believed only with the run's proof, which Codefly generates and delivers to the hop and the module alone. In a cell the mesh plays that part. +The hop and the edge ask the host the composition names in the `authority` +group's `endpoint`, the key every module reads for the same host, so pointing +that key at saas accounts' Connect listener moves them with the modules: +`host:port` and `http://` are the run's plaintext transport (h2c), `https://` is +TLS. A composition that names none reaches the authority module's local service. +Under `hop/ENFORCEMENT=warn` the hop lets through a call the authority verified +and the method's policy would have refused, stamped with that refusal as its +advisory; a call with a missing, unsound or misaddressed Work Context, or one +the authority could not be asked about, is refused in either mode. + This run's hop fronts the console, whose one operation answers who the call is for. Run it from the playground workspace, `playground/`, which composes this repository's modules with the platform's stores and the directory's page: @@ -437,7 +571,21 @@ The marks reach the authority in the delivery, and the authority decides: does not hold (saying what it holds), a method that declares nothing or both, a method the module does not serve. Without it, `Check` answers as before. 3. **The hop** asks `Check` with the method and passes the answer on. It holds - no policy, reads nothing from the module, and polls nothing. + no permission requirements and polls nothing. Codefly supplies its published + route inventory; the selected destination and declared policy method travel + together into the single Check decision. + +A method requirement names a whole resource kind. Delivery rejects a method +requirement containing resource IDs instead of silently dropping its restriction. +A capability restricted to +resource IDs does not satisfy that requirement, even with a wildcard action; +several restricted scopes do not become a whole-kind grant. A whole-kind grant +alongside restricted scopes still satisfies its declared action. Refusals mark +resource-limited holdings in the diagnostic. `Advise` reports the same refusal +without widening or discarding the checked capability, so warn mode can log it. +Checking a capability without a method and reading its resource scope remain +supported. Modules still own resource visibility, ownership and installation +checks; method admission does not replace them. Proven live on 2026-10-23 with the CLI of codefly-dev/cli#1128 at 13f7a3e3: the console's delivery carries its signed document; Maya's `WhoAmI` and `Version` @@ -446,10 +594,10 @@ console method `NotFound`; and a check naming a method at a module whose delivery carried no document is refused, while the same token with no method named is checked as before. -The authority gateway passes the suite line that proves it ("a check naming a +The local authority passes the suite line that proves it ("a check naming a method applies what the module's delivery declares"), which fails when `Check` -ignores the method. Accounts implements neither the document nor the method -yet; the line skips for a fixture that signs no authority document. +ignores the method. Each host must supply a signed authority document and prove the method cases; +an omitted signer fails conformance. Local results do not establish Accounts parity. The console imports the option by copying `policy.proto` into its proto tree, as every module in the fleet copies the option protos it uses. That copy is a @@ -467,7 +615,7 @@ Not yet: `playground/configurations/local/hop.env` lists the console. Composing hops is the composition's job. - **The interface, not the provider.** The SDK resolves an endpoint by its - provider, so the hop names the authority gateway. An accessor by interface is + provider, so the hop names the local authority. An accessor by interface is an SDK change. - **The cell face.** The same decision, called by the mesh's authorization step. @@ -504,7 +652,7 @@ the `approvals` table), as accounts keeps its own in its store when it implement the interface: consent is runtime state a person created, not fixture, and a restart that forgot it refused every run of the approved artifact while the consuming module kept its installation. A run that composes no store keeps -them in memory, and the gateway says which at boot +them in memory, and the local authority says which at boot ([the module page](modules/authority/README.md)). The fixture grants an Acme admin `robin.intents:activate` and an editor `robin.intents:run`. @@ -523,11 +671,20 @@ another site lands on the root, and a non-browser caller signs in with a JSON `fixtureToken`. `/auth/session` answers who is signed in (`personId`, `organizationId`, -`roles`) and the organisation's active `installations`, each `{id, target}`: -the host's navigation read, which a frontend binds its calls to (a robin -conversation names its installation). An installation id is a canonical UUID, -as the host issues, named by organisation and target so it is the same on -every start: a module's stored rows keep naming it. +`roles`), the `installations` the person may use, each `{id, target}`, which a +frontend binds its calls to (a robin conversation names its installation), and +`refused`, the reason for each other target. Both come from `Issue`, once per +module the edge routes, as a call to that module would: a target is usable when +the authority issues the person a Work Context there, and its id is the +installation the context is sealed to. A member reads this as well as an +administrator, so the installation interface's `List`, an administrator's read +a host refuses a member, decides nothing here. A person who holds nothing at a +target and an organisation that never installed it are each refused with the +authority's own words. `List` is asked only for each installation's +`namespace`, which no member's read carries yet, so the namespace is named for +whoever the host lets list. An installation id is a canonical UUID, as the host +issues, named by organisation and target so it is the same on every start: a +module's stored rows keep naming it. Each call is routed by its path: `/v1//…` to the module's REST face, `//…` to its Connect face, and every other path to the @@ -572,11 +729,11 @@ token, so tokens stay small and a new grant takes effect at once. The answer is a list of grants. Each one covers every resource of the kind, one id, an id prefix, or a whole-id RE2 pattern of at most 256 bytes. A resource is covered when any grant matches its id. `libraries/resources/go` is the one -evaluation of grants, used by the authority gateway to validate its roles, by +evaluation of grants, used by the local authority to validate its roles, by the suite, and by any module deciding which of its own resources a caller sees. The authority knows resources by id only; each module maps ids onto its own. -On the authority gateway a role's scope may carry `resources`. A scope with +On the local authority a role's scope may carry `resources`. A scope with none covers the whole kind. A person's answer is what her roles grant. A module's or an installation's own work is bounded by its capability alone. A capability narrowed to named ids covers only the ones the owner's grants also @@ -587,17 +744,17 @@ grant" holds an implementation to a fixture's covered and uncovered ids, an unheld action, and a narrowed capability. It fails on an implementation that answers every resource. -Building it exposed an attenuation bug: the gateway's scope operations dropped +Building it exposed an attenuation bug: the local authority's scope operations dropped resource ids, so a capability asked for two named resources was issued for the whole kind. They now keep ids, and an intersection keeps the narrower side (`pkg/business/state`, with unit tests). The fixture's record kinds are now the record store's own, `records.records` and `records.types`. -## The document store on the authority gateway, no saas (2026-10-23) +## The document store on the local authority, no saas (2026-10-23) Proven live, with the document store from obin-ai/module-document-store's `authority/behind-the-hop` branch (4e295b1) and the record store from its -branch (d506000), composed in this workspace with the authority gateway as host, +branch (d506000), composed in this workspace with the local authority as host, the hop in front of both, and no saas module: | Call | Answer | @@ -610,12 +767,44 @@ the hop in front of both, and no saas module: | The same REST call with no token | HTTP 401 from the hop, naming the gRPC method | | Rémi's token straight to the store's gRPC port | refused: no stamp | -Every manifest reached the authority gateway through the composition interface. +Every manifest reached the local authority through the composition interface. The store's host services (jobs, notifications, approvals, record placement, file fetch) report themselves unwired and idle, and ingest is off because no runtime is composed. The fixture's collection grants do not yet use the store's real namespace spelling. +## Delegated resource restrictions + +A delegation preserves the exact resource IDs supplied in its WorkScopes. +Omitted IDs grant the whole kind, while named IDs remain a ceiling even when +the grantor and operation binding hold broader authority. Delegate, +GetDelegation, Issue, downstream children and RevokeDelegation preserve that +stored ceiling; requesting an ID outside it is refused. The child reconstructs +the target projection from the stored grant, not from the narrower previous +audience's projection. + +Development fixtures use `resource_ids` on delegation scopes. The +`resources` matchers used by roles (IDs, prefixes and patterns) are a separate +contract and are rejected on delegation scopes rather than silently ignored. +The generated gRPC client regression covers the complete delegation lifecycle; +the fixture regression checks exact IDs and matcher-syntax refusal. These are +hermetic local authority checks, not full consumer or SaaS-provider qualification. + +Revoking a delegation advances the organization's authorization revision in the +same state update. Previously issued capabilities, including descendants, then +fail the ordinary core verifier. This is deliberately conservative: outstanding +capabilities throughout that organization are invalidated, while other +organizations are unaffected. Ordinary authorized callers recover by requesting +fresh authority; the revoked delegation cannot issue again. Repeated, unknown +or unauthorized revocations do not advance the revision. + +Issuance rereads the delegation after signing, and parent exchanges recheck the +original parent after signing, to prevent concurrent revocation from being +refreshed into new authority. Regressions cover existing-token checks, resource +discovery, descendants, tenant isolation and deterministic issuance interleavings. +This does not qualify the separate cross-audience attenuation or durable custody +contracts. + ## Every saas module-authority feature, and where it lives now (2026-10-23) A module's saas client (`saas-sdk-go/moduleauthority`) is replaced by this @@ -636,17 +825,19 @@ the interface, with a suite line, or named as belonging elsewhere. | Audit (`EmitAuditEvent`, `DeclareAuditEventTypes`) | not authority: an optional audit interface; with none injected, the module logs each event | the record store | | Notifications and the current installation (`NotifyUser`, `NotifyOrgAdmins`, `GetCurrentInstallation`) | not authority: host services, optional interfaces | open | -The authority gateway implements every line. Accounts implements none of the -last five additions yet (lookup, delegations and their read, `ListResources`, -method policy); -each suite line skips for a fixture that states no case. +The local authority supplies these cases. Each host must run the current suite +against its own provider; missing required fixtures fail. Earlier Accounts +results do not qualify later suite additions. ## Open decisions -- **Decided 2026-10-23, the hop rule.** A module hops only on a person's token - addressed to it, the hop names the binding it exercises, and the person's token - names that binding too, so the child carries exactly what the person holds - through the binding at its audience. Core stands unchanged. The authority gateway +- **Decided 2026-10-23, the hop rule.** A module hops only on a verified token + addressed to it, and the hop names the binding it exercises. Current child + derivation supports person and installation owners through their target grants; + service-owned work remains bounded by its existing effective scopes. The + target-projection and stored-delegation rules above state these distinctions. + Core main `e501458995d05b641ed10e456fcb2837ff8b9f86` supplies action-specific + scope containment; these dependency graphs require Go 1.27.3. The local authority and the suite state it; the host's `childHop` and its person issue follow (saas #1219 is the person half there). History: The host's `module_actor` mode (saas #1215) requires the person's parent to be @@ -669,7 +860,84 @@ each suite line skips for a fixture that states no case. workload's credential (`SignedManifestV1`, `ApplyManifestRequest.carrier` and `.credential`). Each implementation verifies the envelope against the release keys it pins and reads the manifest from the verified document. The mini - gateway pins the kit's release key and attests the carrier by the launcher's + local authority pins the kit's release key and attests the carrier by the launcher's anchor; the host pins its release keys and attests the delivery service account. The sketch (`manifest`) stays through the transition and is ignored when a carrier is present. Not yet done: the host adapter behind it. + +## Local service name (2026-10-25) + +The development implementation is `authority/local`, with `grpc` and `rest` +endpoints. Module and solution playgrounds compose this local authority; the +platform composition uses SaaS locally as its authority interface implementation. +The edge and hop resolve `authority/local/grpc` when no `authority/endpoint` +configuration is supplied. Consumers must update service pins and endpoint +references together. The existing Go module import and protobuf wire identities +remain stable; they do not select the implementation in a composition. + +The local issuer is `codefly.dev/authority/local`; compositions pinning an +expected issuer (including Runtime) must update that configuration alongside the +endpoint selectors. SaaS compositions keep their own issuer and host selection. + +## Tool-call authority tests (2026-10-25) + +An installation-owned `Issue` requires `actor.credential` from that installed +solution's workload. The host verifies it through the same workload verifier used +for ordinary module issuance, then checks that the authenticated module is the +installation's target solution. An installation ID or a signed-in person's +session alone grants nothing. Existing callers must supply the credential; the +shared conformance fixture now requires `InstalledCredential` as well. + +The issuer tests and shared gRPC conformance suite exercise a module's binding to +an installed solution: the entitled person's root carries the binding scope, +the child preserves the person as owner and the module as actor, and a real +method-policy check succeeds. A person without the target entitlement cannot +obtain that permission, including when the child asks for its default scopes. +A solution target bounds the whole child by its person role and binding; ordinary +module-to-module derivation is unchanged. Hosts supply `SolutionTools` to run this +additional shared scenario; a missing scenario fails conformance. + +An installation owner can cross successive module actors in its organisation. +The local seal source associates an active solution installation's agent with +active module installations in that same organisation. The acting module's +binding remains sealed to its own installation, and Core's binding/seal +verification is unchanged. The issuer still derives each target from the +original installation's current role and the binding; the seal association adds +no actions or resource rights. It does not associate an agent with another +solution installation or another organisation. + +Issuer tests cover exact owner/actor provenance, resource restrictions, wrong +actors, source and actor uninstall, role/binding narrowing, and source uninstall +during issuance. Shared conformance hosts supply `InstallationChain` to prove +successive module hops; the local fixture crosses three actors. A missing +fixture fails conformance and is not evidence of provider parity. These are offline +authority tests, not a live solution or SaaS qualification. + +Target-solution consent for installation-owned tool calls is **not implemented**. +The executable regression is deliberately behind the `pending` build tag: +`go test -tags pending ./pkg/business/issuer -run +TestInstallationToolRequiresTargetSolutionConsent` from the local service's +`code/` directory. It currently fails for direct issuance based on the source +solution's role alone; the two-hop case now also issues without target consent. +Neither result proves target consent. The +positive consent relationship and its revocation remain an authority contract +and implementation gap. No target-consent grant was invented, and Core's +binding verification was not bypassed to hide it. + +## Interface evolution, 2026-10-25 + +`codefly.dev/authority@0.2.0` is the breaking successor to 0.1.0. Core's +interface evolution rules require a minor bump below 1.0. Installation Issue +requires its installed caller's workload credential; an installation ID alone +is never authority. Workloads name the work item's organization; the local +sole-installation convenience is not required of other hosts. Advisory Check +is a local development extension, and the hop rejects warn outside local runs. + +`codefly.dev/session@0.2.0` adds person and organization display names to Current +and SignIn (fields 7 and 8). Missing fields fail conformance. These implement the +[host interface use cases](https://github.com/obin-ai/handbook/blob/main/design/host-authority-interface/use-cases.md) +under the existing +[host interface proposal](https://github.com/obin-ai/handbook/blob/main/proposals/2026-10-22-the-host-authority-interface-and-the-local-authority.md). +All consumers and implementations must select the updated interface versions; +this repository updates its module, edge, hop and console declarations. SaaS +must adopt the version and fields before claiming this contract. diff --git a/interfaces/authority/interface.codefly.yaml b/interfaces/authority/interface.codefly.yaml index f28552ed..72c484f2 100644 --- a/interfaces/authority/interface.codefly.yaml +++ b/interfaces/authority/interface.codefly.yaml @@ -1,8 +1,8 @@ kind: interface publisher: codefly.dev name: authority -description: What a module or solution calls on its host to be issued, checked and verified authority. Implemented by accounts and by the authority gateway. -version: 0.1.0 +description: What a module or solution calls on its host to be issued, checked and verified authority. Implemented by accounts and by the local authority. +version: 0.2.0 type: connect protobuf: package: host.authority.v1 diff --git a/interfaces/session/interface.codefly.yaml b/interfaces/session/interface.codefly.yaml index a46558f1..d15479ed 100644 --- a/interfaces/session/interface.codefly.yaml +++ b/interfaces/session/interface.codefly.yaml @@ -2,7 +2,7 @@ kind: interface publisher: codefly.dev name: session description: A person signs in at the browser edge, and a page asks who the bearer it was handed is; a module never calls this. -version: 0.1.0 +version: 0.2.0 type: connect protobuf: package: host.session.v1 diff --git a/libraries/authority-client/contract/catalog.codefly.json b/libraries/authority-client/contract/catalog.codefly.json index 7ad276fc..f83f7a6c 100644 --- a/libraries/authority-client/contract/catalog.codefly.json +++ b/libraries/authority-client/contract/catalog.codefly.json @@ -4,13 +4,13 @@ "version": "0.0.0", "endpoints": [ { - "service": "gateway", + "service": "local", "endpoint": "grpc", "api": "grpc", "kind": "protobuf", "package": "api", "path": "contract.binpb", - "digest": "sha256:89baa9ae5c5f7940f17b303afdb58824e913427d3fb826c81b24f78e5378d599", + "digest": "sha256:d2fcb57f3608ea6c57918565db2d83cc69d7e9cebee33edadf2160a3fee8d635", "services": [ { "name": "GatewayService", diff --git a/libraries/authority-client/contract/contract.binpb b/libraries/authority-client/contract/contract.binpb index 5f888ae9..a9656334 100644 Binary files a/libraries/authority-client/contract/contract.binpb and b/libraries/authority-client/contract/contract.binpb differ diff --git a/libraries/authority-client/go/README.md b/libraries/authority-client/go/README.md new file mode 100644 index 00000000..de8f7548 --- /dev/null +++ b/libraries/authority-client/go/README.md @@ -0,0 +1,48 @@ +# Authority Go client + +Codefly generates the RPC bindings in `gen/`. The `workcontext` package adds a +non-verifying projection using Core's maintained decoder and scope containment: + +```go +import claims "github.com/codefly-dev/authority/libraries/authority-client/go/workcontext" + +// The reader requires incoming metadata and the run-delivered hop proof. +md, _ := metadata.FromIncomingContext(ctx) +c, err := claims.ReadClaims(md, proof) +// Handle err, compare c.Audience() to this module's delivered audience, then: +allowed := c.Allows(resourceKind, action, exactResourceID) +``` + +`Scopes()` returns deep copies of the final actor's grants, or the owner's grants +when there is no actor. An empty final actor grants nothing. `Allows` evaluates +each candidate independently. An empty requested resource ID asks for the entire +kind; a restricted grant cannot satisfy it. Kind-wide grants cover named IDs. +Actions are literal: no admin implication, wildcard expansion, prefix matching +or union of one grant's actions with another's resources. + +The reader checks a bounded canonical envelope and 64-byte signature shape, then +uses Core Decode. Go deliberately retains Core's stronger structural/schema and +attenuation checks; the Python and TypeScript readers only project readable +claims. All three agree on the shared Core-produced fixtures. None verifies a +signature, current time, live revisions or replay. Even a digest-bound context +may have been refused in warning mode. These claims alone never prove authority. +Keep audience, installed-definition, ownership, resource and live-visibility +checks at their existing owners. The exposed protobuf scopes are Core's current +public types during the authority migration; do not mutate returned copies and +expect to change the claims snapshot. + +From this directory, run `GOWORK=off go test -race ./...` and `go vet ./...`. +The tests consume `../testdata/claims.json`, whose gateway-side oracle verifies +Core-minted tokens at a fixed fixture clock. Synthetic mutated tokens in unit +tests exercise parsing only and are not valid credentials. + +Handwritten code lives outside `gen/`, the directory Codefly replaces. The root +module scaffold is preserved by `codefly generate client`. + +The shared `host.Dial` resolves the authority for edge and hop. Remote endpoints +use verified HTTPS/TLS unless the composition asserts +`internal-transport/mesh-protected=true` and the target is an in-cluster Service +DNS name. Plaintext loopback is accepted only in a local Codefly environment. +Configured endpoints and SDK-resolved fallbacks use the same rule. Unreadable or +misspelled mesh assertions refuse before dialing; the shared host client owns +this check for edge and hop, without reviving the retired SDK verifier. diff --git a/libraries/authority-client/go/gen/host/artifact/v1/artifact_grpc.pb.go b/libraries/authority-client/go/gen/host/artifact/v1/artifact_grpc.pb.go index 79785688..914be5f6 100644 --- a/libraries/authority-client/go/gen/host/artifact/v1/artifact_grpc.pb.go +++ b/libraries/authority-client/go/gen/host/artifact/v1/artifact_grpc.pb.go @@ -36,7 +36,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // -// ArtifactService is implemented by the host and by the authority gateway. +// ArtifactService is implemented by the host and by the local authority. type ArtifactServiceClient interface { // Approve records the person's consent to the identity for the installation // under the policy. The person is present: the parent is theirs, addressed @@ -97,7 +97,7 @@ func (c *artifactServiceClient) Revoke(ctx context.Context, in *RevokeRequest, o // All implementations must embed UnimplementedArtifactServiceServer // for forward compatibility. // -// ArtifactService is implemented by the host and by the authority gateway. +// ArtifactService is implemented by the host and by the local authority. type ArtifactServiceServer interface { // Approve records the person's consent to the identity for the installation // under the policy. The person is present: the parent is theirs, addressed diff --git a/libraries/authority-client/go/gen/host/authority/v1/authority.pb.go b/libraries/authority-client/go/gen/host/authority/v1/authority.pb.go index 3ff58762..8a6d6865 100644 --- a/libraries/authority-client/go/gen/host/authority/v1/authority.pb.go +++ b/libraries/authority-client/go/gen/host/authority/v1/authority.pb.go @@ -51,10 +51,13 @@ type IssueRequest struct { // The declared binding this capability exercises, when the owner is a workload // or a child acts through one. OperationBindingId string `protobuf:"bytes,8,opt,name=operation_binding_id,json=operationBindingId,proto3" json:"operation_binding_id,omitempty"` - // The organisation the work runs in, for an owner shape that does not carry one. + // The organisation the work runs in. A workload may leave this empty when + // exactly one organisation has an active installation of its module. + // Otherwise it must name the organisation of the work item; + // absent or ambiguous installation authority is refused with a reason. OrganizationId string `protobuf:"bytes,9,opt,name=organization_id,json=organizationId,proto3" json:"organization_id,omitempty"` - // The actor a child hop delegates to, as a workload credential; required with - // parent_token and with delegation. + // The acting workload credential; required with parent_token, delegation, + // and installation. For installation it must name the installed solution. Actor *WorkloadCredential `protobuf:"bytes,10,opt,name=actor,proto3" json:"actor,omitempty"` // Which of the binding's operations the capability is for: "invoke" (the // default for a person, a child or a delegation), "headless" (the default for @@ -213,6 +216,7 @@ type IssueRequest_Workload struct { type IssueRequest_Installation struct { // An installation acting for itself, with the scope the organisation consented to. + // actor must authenticate a workload of that installation's solution. Installation *InstallationRef `protobuf:"bytes,3,opt,name=installation,proto3,oneof"` } @@ -802,7 +806,14 @@ type CheckRequest struct { // applies what the audience module's delivery declares for that method, and // refuses by name a call that does not hold it, a method that declares // nothing, and a method the module does not serve. - Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"` + Method string `protobuf:"bytes,3,opt,name=method,proto3" json:"method,omitempty"` + // Advisory asks for the policy decision without its refusal: the capability + // is still verified and refused when it is not sound, but what the method + // declares is only reported, in CheckResponse.refusal, and the verified + // capability is answered. A hop in a composition that runs permissive + // (hop/ENFORCEMENT=warn) asks this way and logs the refusal it did not make. + // Hosts may refuse advisory outside local development runs. + Advisory bool `protobuf:"varint,4,opt,name=advisory,proto3" json:"advisory,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -858,6 +869,13 @@ func (x *CheckRequest) GetMethod() string { return "" } +func (x *CheckRequest) GetAdvisory() bool { + if x != nil { + return x.Advisory + } + return false +} + // CheckResponse is the verified capability. type CheckResponse struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -865,8 +883,11 @@ type CheckResponse struct { Context *WorkContextV1 `protobuf:"bytes,1,opt,name=context,proto3" json:"context,omitempty"` // The owner's authorization revision as of this check. AuthorizationRevision uint64 `protobuf:"varint,2,opt,name=authorization_revision,json=authorizationRevision,proto3" json:"authorization_revision,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Refusal is what the method's policy would have refused, verbatim, when the + // check was advisory and the policy did not hold; empty when it held. + Refusal string `protobuf:"bytes,3,opt,name=refusal,proto3" json:"refusal,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CheckResponse) Reset() { @@ -913,6 +934,13 @@ func (x *CheckResponse) GetAuthorizationRevision() uint64 { return 0 } +func (x *CheckResponse) GetRefusal() string { + if x != nil { + return x.Refusal + } + return "" +} + // KeysRequest asks for the verification keys. type KeysRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1367,14 +1395,16 @@ const file_host_authority_v1_authority_proto_rawDesc = "" + "\rIssueResponse\x12\x14\n" + "\x05token\x18\x01 \x01(\tR\x05token\x12&\n" + "\x0fexpires_at_unix\x18\x02 \x01(\x03R\rexpiresAtUnix\x12:\n" + - "\acontext\x18\x03 \x01(\v2 .host.authority.v1.WorkContextV1R\acontext\"X\n" + + "\acontext\x18\x03 \x01(\v2 .host.authority.v1.WorkContextV1R\acontext\"t\n" + "\fCheckRequest\x12\x14\n" + "\x05token\x18\x01 \x01(\tR\x05token\x12\x1a\n" + "\baudience\x18\x02 \x01(\tR\baudience\x12\x16\n" + - "\x06method\x18\x03 \x01(\tR\x06method\"\x82\x01\n" + + "\x06method\x18\x03 \x01(\tR\x06method\x12\x1a\n" + + "\badvisory\x18\x04 \x01(\bR\badvisory\"\x9c\x01\n" + "\rCheckResponse\x12:\n" + "\acontext\x18\x01 \x01(\v2 .host.authority.v1.WorkContextV1R\acontext\x125\n" + - "\x16authorization_revision\x18\x02 \x01(\x04R\x15authorizationRevision\"\r\n" + + "\x16authorization_revision\x18\x02 \x01(\x04R\x15authorizationRevision\x12\x18\n" + + "\arefusal\x18\x03 \x01(\tR\arefusal\"\r\n" + "\vKeysRequest\"X\n" + "\fKeysResponse\x12\x16\n" + "\x06issuer\x18\x01 \x01(\tR\x06issuer\x120\n" + diff --git a/libraries/authority-client/go/gen/host/authority/v1/authority_grpc.pb.go b/libraries/authority-client/go/gen/host/authority/v1/authority_grpc.pb.go index 046e7fa4..51d772ee 100644 --- a/libraries/authority-client/go/gen/host/authority/v1/authority_grpc.pb.go +++ b/libraries/authority-client/go/gen/host/authority/v1/authority_grpc.pb.go @@ -39,7 +39,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // -// AuthorityService is implemented by the host (accounts) and by the authority gateway. +// AuthorityService is implemented by the host (accounts) and by the local authority. type AuthorityServiceClient interface { // Issue signs a Work Context for one owner shape, one audience and the scopes // asked for, bounded by what the owner holds and what the audience declared. @@ -151,7 +151,7 @@ func (c *authorityServiceClient) GetDelegation(ctx context.Context, in *GetDeleg // All implementations must embed UnimplementedAuthorityServiceServer // for forward compatibility. // -// AuthorityService is implemented by the host (accounts) and by the authority gateway. +// AuthorityService is implemented by the host (accounts) and by the local authority. type AuthorityServiceServer interface { // Issue signs a Work Context for one owner shape, one audience and the scopes // asked for, bounded by what the owner holds and what the audience declared. diff --git a/libraries/authority-client/go/gen/host/composition/v1/composition.pb.go b/libraries/authority-client/go/gen/host/composition/v1/composition.pb.go index 156549b7..606daa51 100644 --- a/libraries/authority-client/go/gen/host/composition/v1/composition.pb.go +++ b/libraries/authority-client/go/gen/host/composition/v1/composition.pb.go @@ -38,10 +38,10 @@ type ApplyManifestRequest struct { // envelope over it. An implementation verifies the envelope against the release // keys it pins and reads the manifest from the verified document, never from // the request, so what composes a module is the same signed document on the - // authority gateway and on the host. + // local authority and on the host. Carrier *SignedManifestV1 `protobuf:"bytes,2,opt,name=carrier,proto3" json:"carrier,omitempty"` // The credential of the workload delivering the manifest, as that - // implementation attests workloads: the launcher's on the authority gateway, the + // implementation attests workloads: the launcher's on the local authority, the // delivery service account's on the host. A manifest is delivered by its own // module's delivery workload and by nothing else. Credential string `protobuf:"bytes,3,opt,name=credential,proto3" json:"credential,omitempty"` @@ -132,7 +132,8 @@ type AuthorityManifestV1 struct { ScopeCeilings []*v1.WorkScopeV1 `protobuf:"bytes,5,rep,name=scope_ceilings,json=scopeCeilings,proto3" json:"scope_ceilings,omitempty"` // The roles a solution declares a person may hold on an installation of it, // as ModuleManifestV1.roles declares them through the sketch: each within - // the solution's own kinds (its scope ceilings), one of them installer. + // the solution's own scope ceilings or explicit invoke/lookup binding scopes, + // one of them installer. Headless-only scopes cannot supply a role grant. // Core's manifest carries no roles, so they travel here until it does. A // module declares none; a module's delivery listing any is refused. Roles []*RoleV1 `protobuf:"bytes,6,rep,name=roles,proto3" json:"roles,omitempty"` @@ -415,8 +416,9 @@ type ModuleManifestV1 struct { // The page the module contributes, if any. Page *PageV1 `protobuf:"bytes,7,opt,name=page,proto3" json:"page,omitempty"` // The roles a solution declares a person may hold on an installation of it, - // each within what the solution serves; one is named installer, held by - // whoever installs it. A module declares none. + // each within what the solution serves or explicitly consumes through + // invoke/lookup bindings; one is named installer, held by whoever installs it. + // Headless-only scopes cannot supply a role grant. A module declares none. Roles []*RoleV1 `protobuf:"bytes,8,rep,name=roles,proto3" json:"roles,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache diff --git a/libraries/authority-client/go/gen/host/composition/v1/composition_grpc.pb.go b/libraries/authority-client/go/gen/host/composition/v1/composition_grpc.pb.go index 359654b6..4ecc26c4 100644 --- a/libraries/authority-client/go/gen/host/composition/v1/composition_grpc.pb.go +++ b/libraries/authority-client/go/gen/host/composition/v1/composition_grpc.pb.go @@ -32,7 +32,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // -// CompositionService is implemented by the host and by the authority gateway. +// CompositionService is implemented by the host and by the local authority. type CompositionServiceClient interface { // ApplyManifest delivers one module instance's manifest at one generation. ApplyManifest(ctx context.Context, in *ApplyManifestRequest, opts ...grpc.CallOption) (*ApplyManifestResponse, error) @@ -60,7 +60,7 @@ func (c *compositionServiceClient) ApplyManifest(ctx context.Context, in *ApplyM // All implementations must embed UnimplementedCompositionServiceServer // for forward compatibility. // -// CompositionService is implemented by the host and by the authority gateway. +// CompositionService is implemented by the host and by the local authority. type CompositionServiceServer interface { // ApplyManifest delivers one module instance's manifest at one generation. ApplyManifest(context.Context, *ApplyManifestRequest) (*ApplyManifestResponse, error) diff --git a/libraries/authority-client/go/gen/host/installation/v1/installation_grpc.pb.go b/libraries/authority-client/go/gen/host/installation/v1/installation_grpc.pb.go index b1b79901..8d5c6fea 100644 --- a/libraries/authority-client/go/gen/host/installation/v1/installation_grpc.pb.go +++ b/libraries/authority-client/go/gen/host/installation/v1/installation_grpc.pb.go @@ -33,7 +33,7 @@ const ( // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // -// InstallationService is implemented by the host and by the authority gateway. +// InstallationService is implemented by the host and by the local authority. type InstallationServiceClient interface { // Install composes an installation: its agent principal, its root scope and // the row, pending until the target acknowledges its install step. @@ -88,7 +88,7 @@ func (c *installationServiceClient) List(ctx context.Context, in *ListRequest, o // All implementations must embed UnimplementedInstallationServiceServer // for forward compatibility. // -// InstallationService is implemented by the host and by the authority gateway. +// InstallationService is implemented by the host and by the local authority. type InstallationServiceServer interface { // Install composes an installation: its agent principal, its root scope and // the row, pending until the target acknowledges its install step. diff --git a/libraries/authority-client/go/gen/host/session/v1/session.pb.go b/libraries/authority-client/go/gen/host/session/v1/session.pb.go index 39d48b5b..1324aeeb 100644 --- a/libraries/authority-client/go/gen/host/session/v1/session.pb.go +++ b/libraries/authority-client/go/gen/host/session/v1/session.pb.go @@ -6,7 +6,7 @@ // The session interface, at the browser edge: a person signs in and the host // opens a session, and a page's runtime asks who the bearer a request carries is. -// The authority gateway signs in fixture people; the host signs in real ones. A +// The local authority signs in fixture people; the host signs in real ones. A // module never calls this: it is called through the hop. package sessionv1 @@ -299,11 +299,15 @@ type Session struct { // The teams belonged to. TeamIds []string `protobuf:"bytes,5,rep,name=team_ids,json=teamIds,proto3" json:"team_ids,omitempty"` // The credential the person presents on every call as `authorization: Bearer - // `; whatever this implementation authenticates a person by. The mini - // gateway hands back the session id; the host hands back its access token. - Bearer string `protobuf:"bytes,6,opt,name=bearer,proto3" json:"bearer,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // `; whatever this implementation authenticates a person by. The local + // authority hands back the session id; the host hands back its access token. + Bearer string `protobuf:"bytes,6,opt,name=bearer,proto3" json:"bearer,omitempty"` + // The person's display name, for the browser session surface. + PersonDisplayName string `protobuf:"bytes,7,opt,name=person_display_name,json=personDisplayName,proto3" json:"person_display_name,omitempty"` + // The signed-in organisation's display name. + OrganizationDisplayName string `protobuf:"bytes,8,opt,name=organization_display_name,json=organizationDisplayName,proto3" json:"organization_display_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Session) Reset() { @@ -378,6 +382,20 @@ func (x *Session) GetBearer() string { return "" } +func (x *Session) GetPersonDisplayName() string { + if x != nil { + return x.PersonDisplayName + } + return "" +} + +func (x *Session) GetOrganizationDisplayName() string { + if x != nil { + return x.OrganizationDisplayName + } + return "" +} + var File_host_session_v1_session_proto protoreflect.FileDescriptor const file_host_session_v1_session_proto_rawDesc = "" + @@ -395,7 +413,7 @@ const file_host_session_v1_session_proto_rawDesc = "" + "\rfixture_token\x18\x06 \x01(\tR\ffixtureToken\"\x10\n" + "\x0eCurrentRequest\"4\n" + "\rSignInRequest\x12#\n" + - "\rfixture_token\x18\x01 \x01(\tR\ffixtureToken\"\xb7\x01\n" + + "\rfixture_token\x18\x01 \x01(\tR\ffixtureToken\"\xa3\x02\n" + "\aSession\x12\x1d\n" + "\n" + "session_id\x18\x01 \x01(\tR\tsessionId\x12\x1b\n" + @@ -403,7 +421,9 @@ const file_host_session_v1_session_proto_rawDesc = "" + "\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\x12\x14\n" + "\x05roles\x18\x04 \x03(\tR\x05roles\x12\x19\n" + "\bteam_ids\x18\x05 \x03(\tR\ateamIds\x12\x16\n" + - "\x06bearer\x18\x06 \x01(\tR\x06bearer2\xe0\x02\n" + + "\x06bearer\x18\x06 \x01(\tR\x06bearer\x12.\n" + + "\x13person_display_name\x18\a \x01(\tR\x11personDisplayName\x12:\n" + + "\x19organization_display_name\x18\b \x01(\tR\x17organizationDisplayName2\xe0\x02\n" + "\x0eSessionService\x12b\n" + "\x06SignIn\x12\x1e.host.session.v1.SignInRequest\x1a\x18.host.session.v1.Session\"\x1e\x82\xd3\xe4\x93\x02\x18:\x01*\"\x13/v1/session:sign-in\x12Y\n" + "\aCurrent\x12\x1f.host.session.v1.CurrentRequest\x1a\x18.host.session.v1.Session\"\x13\x82\xd3\xe4\x93\x02\r\x12\v/v1/session\x12\x8e\x01\n" + diff --git a/libraries/authority-client/go/gen/host/session/v1/session_grpc.pb.go b/libraries/authority-client/go/gen/host/session/v1/session_grpc.pb.go index f457e368..70bcdb0e 100644 --- a/libraries/authority-client/go/gen/host/session/v1/session_grpc.pb.go +++ b/libraries/authority-client/go/gen/host/session/v1/session_grpc.pb.go @@ -6,7 +6,7 @@ // The session interface, at the browser edge: a person signs in and the host // opens a session, and a page's runtime asks who the bearer a request carries is. -// The authority gateway signs in fixture people; the host signs in real ones. A +// The local authority signs in fixture people; the host signs in real ones. A // module never calls this: it is called through the hop. package sessionv1 diff --git a/libraries/authority-client/go/go.mod b/libraries/authority-client/go/go.mod index 29687193..cf15718c 100644 --- a/libraries/authority-client/go/go.mod +++ b/libraries/authority-client/go/go.mod @@ -1,17 +1,52 @@ module github.com/codefly-dev/authority/libraries/authority-client/go -go 1.26.0 +go 1.27.3 require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 + github.com/codefly-dev/core v0.19.7-0.20261025185759-e501458995d0 + github.com/codefly-dev/sdk-go v0.4.0 google.golang.org/genproto/googleapis/api v0.0.0-20261019180522-ce908d29299b google.golang.org/grpc v1.84.0 google.golang.org/protobuf v1.36.12 ) require ( - golang.org/x/net v0.57.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/text v0.40.0 // indirect + buf.build/go/protovalidate v1.4.0 // indirect + cel.dev/cel-go v0.32.0 // indirect + cel.dev/expr v0.25.3 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/semver/v3 v3.5.0 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/go-openapi/analysis v1.0.0 // indirect + github.com/go-openapi/errors v0.22.9 // indirect + github.com/go-openapi/jsonpointer v1.0.1 // indirect + github.com/go-openapi/jsonreference v1.0.2 // indirect + github.com/go-openapi/loads v0.25.3 // indirect + github.com/go-openapi/spec v1.0.1 // indirect + github.com/go-openapi/strfmt v0.27.2 // indirect + github.com/go-openapi/swag/conv v0.29.2 // indirect + github.com/go-openapi/swag/jsonutils v0.29.2 // indirect + github.com/go-openapi/swag/loading v0.29.2 // indirect + github.com/go-openapi/swag/mangling v0.29.2 // indirect + github.com/go-openapi/swag/pools v0.29.2 // indirect + github.com/go-openapi/swag/stringutils v0.29.2 // indirect + github.com/go-openapi/swag/typeutils v0.29.2 // indirect + github.com/go-openapi/swag/yamlutils v0.29.2 // indirect + github.com/go-viper/mapstructure/v2 v2.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/oklog/ulid/v2 v2.1.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/yoheimuta/go-protoparser/v4 v4.14.2 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba // indirect + golang.org/x/net v0.60.0 // indirect + golang.org/x/sys v0.49.0 // indirect + golang.org/x/term v0.46.0 // indirect + golang.org/x/text v0.42.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20261012220534-4341edf3f941 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/libraries/authority-client/go/go.sum b/libraries/authority-client/go/go.sum index eefd92f5..5ce30c7c 100644 --- a/libraries/authority-client/go/go.sum +++ b/libraries/authority-client/go/go.sum @@ -1,15 +1,207 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2 h1:NbnlmV26O7oZ1iM5tsCI+GEx+3ZSdrhvnKQ/eWSrLiY= buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.12-20260825204119-511051f7f437.2/go.mod h1:TCt1lluMFnctISJXvkIQ4x3ABrPuUKCWKyjKdkJNBpw= +buf.build/go/protovalidate v1.4.0 h1:UjLrYbt5VX7+TMOs2+pG5FhZhIG1mSfK4EIopbb4LcM= +buf.build/go/protovalidate v1.4.0/go.mod h1:8vJfzNT6NIG2qm3uFsJDXMlRmG+bQJzbcIn1Aa0vPGs= +cel.dev/cel-go v0.32.0 h1:irvpFKr5EuGPyxeME03ERh0rii1TX+BDAnB9eL3IvNk= +cel.dev/cel-go v0.32.0/go.mod h1:DnVip7tpJSsgZymwfT+m1tnEVy3ivAjSMXPx12YrMkU= +cel.dev/expr v0.25.3 h1:A2jO8jwOugrrovveCWfj0KEZOfqiLgAcwjpHPhzIGw0= +cel.dev/expr v0.25.3/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.5.0 h1:kQceYJfbupGfZOKZQg0kou0DgAKhzDg2NZPAwZ/2OOE= +github.com/Masterminds/semver/v3 v3.5.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= +github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4= +github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb/v3 v3.2.1 h1:aprZbFRG+B7+ug76S8QZ6Y1PW168UHzOmbC3wa+aU6I= +github.com/cheggaaa/pb/v3 v3.2.1/go.mod h1:U9hSVxoKqJrZIE3PkFG1xXXNaK/Ilzg+EF/scpXzEdw= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/codefly-dev/core v0.19.7-0.20261025185759-e501458995d0 h1:YEFvkyokBsUWbHoaoKOi6iJtMrqNNR7HsWdUQGN50TA= +github.com/codefly-dev/core v0.19.7-0.20261025185759-e501458995d0/go.mod h1:1ina3kP+YSAL4tlZvnEYd4P8bFGnJECfkP86ojeeF1A= +github.com/codefly-dev/gortk v0.2.0 h1:7bOlS5valYz2zil+fZctQNcPCYBcPj86abcw9N8h1hQ= +github.com/codefly-dev/gortk v0.2.0/go.mod h1:dDWUMFgAP063OCGhTEpV7FFUj9+zTcxxO/nV80VKEwg= +github.com/codefly-dev/sdk-go v0.4.0 h1:3Jm0bP+UsLI4iZYp3wqVa42bcXBumMIIF/aeweKOAhY= +github.com/codefly-dev/sdk-go v0.4.0/go.mod h1:vExvoK8jqWNiUjmphgaK/ir1+Tz717mNS6bc4FAHVks= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= +github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.8.2 h1:9d9DEokx5W7qlr0shkFXIxEA7+TTD+llwzcykSlxMNc= +github.com/docker/go-connections v0.8.2/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/felixge/httpsnoop v1.1.0 h1:3YtUj32ZZkqZtt3sZZsClsymw/QDuVfpNhoA31zeORc= +github.com/felixge/httpsnoop v1.1.0/go.mod h1:Zqxgdd+1Rkcz8euOqdr7lqgCRJztwr5hp9vDSi5UZCE= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= +github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/analysis v1.0.0 h1:sNvbAGCJqUTqIAodr9IVqJMmuZas3YS9ms1dGK9yiJ4= +github.com/go-openapi/analysis v1.0.0/go.mod h1:NhYjJ57fnE+bcE7UwrJyMkhWA3Dfz7TdiBfTVAnos4Y= +github.com/go-openapi/errors v0.22.9 h1:HI9+SyVYiRzyeBQGv0CbWbQa+u2S0nny7G7AhY+UMiM= +github.com/go-openapi/errors v0.22.9/go.mod h1:R73q66sXP2smzAGgFOI4nqtusRK2xN5pYCjsij+KX58= +github.com/go-openapi/jsonpointer v1.0.1 h1:2KxywRmNwJkT/FMBa3iRNHEaAxSJvjqoufQZy3au1Mg= +github.com/go-openapi/jsonpointer v1.0.1/go.mod h1:wI7ZYsFmbIi9nBXOZqgDaS/bqOchRGZjqxFli7FBYxY= +github.com/go-openapi/jsonreference v1.0.2 h1:oS4et8FOf3p3UQxEo4Xt0esijmBUM+F259Xl72OSZsc= +github.com/go-openapi/jsonreference v1.0.2/go.mod h1:TbUNSOo+fcorZjFaNoiSDSoaNnnZtqJtLGR1PuvE/Cs= +github.com/go-openapi/loads v0.25.3 h1:V+jKy/thXWdLJUuYC8sZX2dICyAa8M3DokF70jj34P0= +github.com/go-openapi/loads v0.25.3/go.mod h1:LgLyCSOLBL2Qnj0Ps1oo2YH8jZoEKsMeVZCc+ALIxFo= +github.com/go-openapi/spec v1.0.1 h1:lj2vdGpNDcVgwRc6qXdw6qt/KQpCtSa9tnUH6vpDPDk= +github.com/go-openapi/spec v1.0.1/go.mod h1:M//GWQGtDUAjnP37gE6fInLgaczB+FatoipV3H1fYw8= +github.com/go-openapi/strfmt v0.27.2 h1:SG32SlbwNy92s0KJiVxt2joJeFdqIYHvwrA0OU6HqzQ= +github.com/go-openapi/strfmt v0.27.2/go.mod h1:M4CKsMO0Fb8qR10+1Ra75wCKNNquy+Vj+4LWZrhTo2E= +github.com/go-openapi/swag v0.29.2 h1:9n8frkcsuQRA0INU31VbxNxt1zBaHxrHYGEf5BUjFi4= +github.com/go-openapi/swag v0.29.2/go.mod h1:RkCiX1gCVXWgLOavDXE3ALJrQ/VO2ziiIzOUs3z10xo= +github.com/go-openapi/swag/cmdutils v0.29.2 h1:cXEzX/nWCODon251f+1HgL75/R4XXML5IZxgLCWMoro= +github.com/go-openapi/swag/cmdutils v0.29.2/go.mod h1:XziaSVzYqkDvpWXzASfWajw2YvJrLscq610O2XiyqJw= +github.com/go-openapi/swag/conv v0.29.2 h1:8c9shoB8l0QRSR6ymq1llHdBWDqpIgJfjTGHx3Vuhm0= +github.com/go-openapi/swag/conv v0.29.2/go.mod h1:AZS0YigTNf8qNtD6WqJz/N4RUNmpr76SyjFGkq4+p6Q= +github.com/go-openapi/swag/fileutils v0.29.2 h1:mdUL+Vw5ah1fO1AvFCoHeIyv7YZsCz2MN3KNqd/lLVI= +github.com/go-openapi/swag/fileutils v0.29.2/go.mod h1:7QKmmodjAebaq61lGVJa8ldLdGeMF4DSgYv8tXOGGo0= +github.com/go-openapi/swag/jsonutils v0.29.2 h1:uZNSD2/rJDYAfvsLYkykTzXuyxM3QpDKV9jhRHrMu6k= +github.com/go-openapi/swag/jsonutils v0.29.2/go.mod h1:ONTdNvj3Y+IXRzfa17E+Rgt2ns/qiSOYjIo2K7v2yDs= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2 h1:w+Fd6EBOMGlC74GYGHqCLGyb3Bpams8TtNrgM/SG4jo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.29.2/go.mod h1:HC2egPORFzbj/gf05Zrfgz8Mgplx3oW7hgGi7pjZVhM= +github.com/go-openapi/swag/loading v0.29.2 h1:QU1ry24e6r6Shoxe380Nx0X5iKkpRO+hJffsyJ2dVlY= +github.com/go-openapi/swag/loading v0.29.2/go.mod h1:DqilDjuiJKETecsS4TRopWG1acUDsfqN39ZmQhPu6uI= +github.com/go-openapi/swag/mangling v0.29.2 h1:ltdo3K0tTP4P6zWhVVWDU9D37/YYBuMJRdZxiS2Dtog= +github.com/go-openapi/swag/mangling v0.29.2/go.mod h1:RjDi4TnItAenS3cgCXSpIl1kKbjG7il6pnmQVl/8bp8= +github.com/go-openapi/swag/netutils v0.29.2 h1:dBli6jyUa93sDS/XYWShJzf4+nnVfFKfvY9SLUaUzB8= +github.com/go-openapi/swag/netutils v0.29.2/go.mod h1:1pM6Xg/Um8E1eps3umWl8Hme3ByWXOtHsvFC0CULHUE= +github.com/go-openapi/swag/pools v0.29.2 h1:PlGoDRF8WtSyXkedZZkpW3f9wDhFf3u8KtaBcmgmh8c= +github.com/go-openapi/swag/pools v0.29.2/go.mod h1:V3lhxVT4qDYRqc2MRSSbLsTYIYV/2HlHafhyEkmzLIc= +github.com/go-openapi/swag/stringutils v0.29.2 h1:lcnBxwAaysT3bMUVBfn9V/PkfVqkurpqufKU6rTUMGk= +github.com/go-openapi/swag/stringutils v0.29.2/go.mod h1:i9cdh7sGaa0nm3CqIvH5IM5h2QClk1wns2ktKeILvRI= +github.com/go-openapi/swag/typeutils v0.29.2 h1:O7aVvkTs3pXwikgtrPLenigEMdQFgONKRooQA9pgf2I= +github.com/go-openapi/swag/typeutils v0.29.2/go.mod h1:7+GDG+uz9Ke+eVt4rClZg7wklSDp8hT/mKNh/pC26TE= +github.com/go-openapi/swag/yamlutils v0.29.2 h1:IFKFFeDnuIwzfsuWRQU+rI8iL3g4XyAYjV/RlnlxPLM= +github.com/go-openapi/swag/yamlutils v0.29.2/go.mod h1:7MGqtcrK73sxQ4ceiyIf8qiXS/s09JLMdR5esK5euYQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.7.0 h1:wPW6YRgx3+SID1yUy/Xwa17L8kFEaEKod2VRbJDZNUs= +github.com/go-openapi/testify/enable/yaml/v2 v2.7.0/go.mod h1:mI1M88etYbc3PhgHsWQK2kwvNwW5aGFqMPbmib+SGIs= +github.com/go-openapi/testify/v2 v2.8.0 h1:19QDx5b57p8KjO2E4sgs/woL4Akp+FGLRlVm2xn0Rho= +github.com/go-openapi/testify/v2 v2.8.0/go.mod h1:4gUN8jC+RqOE2qjW/vDmfyTvl5BCht4qL7oca0odrak= +github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= +github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/gofrs/flock v0.13.1 h1:jjREztyBeSKBZYAC+mgc1laB+xsgy4kYMf3FbKF2UBo= +github.com/gofrs/flock v0.13.1/go.mod h1:sf4BFiHwnvgxa25DlQoDqXQnwRMEOwqxRq37P6MzzmE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +github.com/google/go-github/v89 v89.0.0 h1:35bEK5XoEcF3PZrlVbl9XN63f5BcJRA/UGkxeC9xPg0= +github.com/google/go-github/v89 v89.0.0/go.mod h1:QLcbU0ipeAqQuR5KSg8c2lql4Qk1EwJ2dWz/0rP4Nho= +github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= +github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e h1:Q6MvJtQK/iRcRtzAscm/zF23XxJlbECiGPyRicsX+Ak= +github.com/lufia/plan9stats v0.0.0-20260330125221-c963978e514e/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= +github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= +github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= +github.com/mattn/go-runewidth v0.0.27 h1:Feg/Oou5zI/wnpgDF6omIU0OokC9GxLC/WRknhVlIR0= +github.com/mattn/go-runewidth v0.0.27/go.mod h1:3qAiGCV4Koz/yuveO58qUefmUTRm8r0IGEXZ9jeHp/8= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= +github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/oklog/ulid/v2 v2.1.2 h1:IEclFb9JNvzYA6MW2SCxbLzcHTVsfqm3PrqGQJH5zec= +github.com/oklog/ulid/v2 v2.1.2/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8= +github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= +github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/shoenig/go-m1cpu v0.2.1 h1:yqRB4fvOge2+FyRXFkXqsyMoqPazv14Yyy+iyccT2E4= +github.com/shoenig/go-m1cpu v0.2.1/go.mod h1:KkDOw6m3ZJQAPHbrzkZki4hnx+pDRR1Lo+ldA56wD5w= +github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE= +github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg= +github.com/tklauser/go-sysconf v0.4.0 h1:7H0uAN+7RkwWRaxhYXDLqa5V3LPrJeV8wmD9dRUgPQU= +github.com/tklauser/go-sysconf v0.4.0/go.mod h1:8mTNWyog7H+MpKijp4VmKJAd2bbYQ2zuUwkYRbUArPI= +github.com/tklauser/numcpus v0.12.0 h1:NR85qdvHA9pFse3x3weVZ0r0ST8R6l5RHbZrlRaqob4= +github.com/tklauser/numcpus v0.12.0/go.mod h1:ABHeXzJnr/qqwguhClkZKT1/8VABcYrsyUiUGobwWJg= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yoheimuta/go-protoparser/v4 v4.14.2 h1:/P/LlX1CF9NaTWEltGcIZVvNlPbhABuAnBtAWpb3+74= +github.com/yoheimuta/go-protoparser/v4 v4.14.2/go.mod h1:AHNNnSWnb0UoL4QgHPiOAg2BniQceFscPI5X/BZNHl8= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0 h1:Tq+E65HaNbZTeqcLw6QUhsV+/EIWdkfUH2CQzcrlE5M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.72.0/go.mod h1:A+EVhDakAj1waJBPhmTszZaSr08ww8MRRKy1nB1rqck= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0 h1:3g7B90UzBltIDKq1/5mrTGxTnOFDV0ICOhLoxiZ8jlg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.71.0/go.mod h1:Ef8SuTh59BT7+ofpDxN9z+yOlc4t2GjLmKDgYNJL/NU= +go.opentelemetry.io/otel v1.47.0 h1:j7ALJ/zgkS7Z6aeJW09p8VC9804bC+PpeTfCD4XPnOM= +go.opentelemetry.io/otel v1.47.0/go.mod h1:8wS9O2qfXrYrzp6hIF/HOYJJf/wIhFPhR2xLuP+iXQU= +go.opentelemetry.io/otel/log v1.47.0 h1:cOTS1CcLbSQeZKanGJ+0JpF/+t4PELi3O3bbl2lqCcI= +go.opentelemetry.io/otel/log v1.47.0/go.mod h1:9byitSQ5pLC6PpqwGXjqdMKya6ZTswHRZh2vvXT33nw= +go.opentelemetry.io/otel/metric v1.47.0 h1:4PptaldXx3Eat1XjMZ68pPJEs5wrhlemctZE9a3UdWY= +go.opentelemetry.io/otel/metric v1.47.0/go.mod h1:ADGSXxRrXM6bjbvLo535EstVFlPpPYZm4LBKixjDHwU= +go.opentelemetry.io/otel/trace v1.47.0 h1:JOjX/Oci8K94QHddo+bbfya/Ai/nf6/dt9ZfrFNWSrM= +go.opentelemetry.io/otel/trace v1.47.0/go.mod h1:jNaSLa2PZEYFG6fRjJABAu+bw4FS08uDmPg28lTghu0= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= +go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= +golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba h1:Ck8QetSgk912qxWLMCKxd0in+aiyBQyDSMae6e/xmpU= +golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba/go.mod h1:50RgIsmK7OwqzTTeqcSXQW8SswW0o8fRcDxmqGluJ8E= +golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU= +golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= +golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE= +golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/api v0.0.0-20261019180522-ce908d29299b h1:nB3spRIaSPtxJpxb0k41yljROvm2Jrwfs2pSNdKS5y8= @@ -20,3 +212,17 @@ google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0= google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad h1:oXImqH8mQNk7PmvzKhmN3ddJoY6OnyM225MXwGHPm0A= +k8s.io/kube-openapi v0.0.0-20260721132016-d427ff9ee9ad/go.mod h1:0/mqHCVhlumdJ3BhCfnjSZQE037nAhNodh1/hK0T8/I= +sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs= +sigs.k8s.io/kustomize/api v0.21.1/go.mod h1:f3wkKByTrgpgltLgySCntrYoq5d3q7aaxveSagwTlwI= +sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7fI= +sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/libraries/authority-client/go/host/host.go b/libraries/authority-client/go/host/host.go new file mode 100644 index 00000000..d8532ecb --- /dev/null +++ b/libraries/authority-client/go/host/host.go @@ -0,0 +1,146 @@ +// Package host resolves and securely dials the composed authority host. +package host + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "net/url" + "strings" + + codefly "github.com/codefly-dev/sdk-go" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" +) + +// Dial connects to the host the edge calls (the authority, session and +// installation interfaces). The composition names it in the authority group's +// endpoint, the key every module reads for the same host; a composition that +// names none reaches the authority module's local authority, as before. +func Dial(ctx context.Context) (*grpc.ClientConn, string, error) { + endpoint, _, err := codefly.For(ctx).WorkspaceValueIfSet("authority", "endpoint") + if err != nil { + return nil, "", fmt.Errorf("authority/endpoint cannot be read: %w", err) + } + target, transport, err := targetFor(ctx, endpoint, func() (string, error) { + local, err := codefly.For(ctx).Module("authority").Service("local").API("grpc").ResolveNetworkInstance() + if err != nil || local == nil { + return "", fmt.Errorf("the composition names no authority/endpoint and the local authority (authority/local) is not resolved: %v", err) + } + return local.Host, nil + }) + if err != nil { + return nil, "", err + } + conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(transport)) + return conn, target, err +} + +// Target is the gRPC target and transport for the host at endpoint: +// HTTPS uses verified TLS. Plaintext requires a local loopback or the +// composition's literal mesh assertion and an in-cluster Service address. +// The SDK-resolved fallback follows the same rule. +func Target(endpoint string, fallback func() (string, error)) (string, credentials.TransportCredentials, error) { + return targetFor(context.Background(), endpoint, fallback) +} + +// Endpoint validates an explicit upstream with the same transport rule as Dial. +// It carries the caller's SDK context so mesh/local decisions have one source. +func Endpoint(ctx context.Context, endpoint string) (string, credentials.TransportCredentials, error) { + return targetFor(ctx, endpoint, nil) +} + +func targetFor(ctx context.Context, endpoint string, fallback func() (string, error)) (string, credentials.TransportCredentials, error) { + mesh, err := meshProtected(codefly.For(ctx).WorkspaceValueIfSet) + if err != nil { + return "", nil, err + } + + endpoint = strings.TrimSpace(endpoint) + if endpoint == "" { + if fallback == nil { + return "", nil, fmt.Errorf("transport endpoint is empty; supply a resolved endpoint") + } + target, err := fallback() + if err != nil { + return "", nil, err + } + return plaintext(target, codefly.IsLocal(), mesh) + } + if !strings.Contains(endpoint, "://") { + if _, _, err := net.SplitHostPort(endpoint); err != nil { + return "", nil, fmt.Errorf("authority/endpoint %q is neither host:port nor a URL", endpoint) + } + return plaintext(endpoint, codefly.IsLocal(), mesh) + } + u, err := url.Parse(endpoint) + if err != nil || u.Host == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || (u.Path != "" && u.Path != "/") { + return "", nil, fmt.Errorf("authority/endpoint %q is not an origin", endpoint) + } + switch u.Scheme { + case "https": + return withPort(u, "443"), credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}), nil + case "http", "grpc", "tcp": + return plaintext(withPort(u, "80"), codefly.IsLocal(), mesh) + default: + return "", nil, fmt.Errorf("authority/endpoint %q names scheme %q; the host is reached over http:// (h2c) or https://", endpoint, u.Scheme) + } +} + +func withPort(u *url.URL, port string) string { + if u.Port() != "" { + return u.Host + } + return net.JoinHostPort(u.Hostname(), port) +} + +func plaintext(target string, local, mesh bool) (string, credentials.TransportCredentials, error) { + hostname, _, err := net.SplitHostPort(target) + if err != nil { + return "", nil, fmt.Errorf("authority endpoint must name host:port") + } + ip := net.ParseIP(hostname) + loopback := strings.EqualFold(hostname, "localhost") || ip != nil && ip.IsLoopback() + if !(local && loopback) && !(mesh && clusterServiceHost(hostname)) { + return "", nil, fmt.Errorf("authority endpoint requires HTTPS, local loopback, or an in-cluster Service address with internal-transport/mesh-protected=true") + } + return target, insecure.NewCredentials(), nil +} + +func meshProtected(read func(string, string) (string, bool, error)) (bool, error) { + value, set, err := read("internal-transport", "mesh-protected") + if err != nil { + return false, fmt.Errorf("internal-transport/mesh-protected could not be read") + } + if !set || value == "" || value == "false" { + return false, nil + } + if value != "true" { + return false, fmt.Errorf("internal-transport/mesh-protected must be exactly true or false") + } + return true, nil +} + +// The mesh assertion covers Service DNS names, never arbitrary hosts or IPs. +func clusterServiceHost(hostname string) bool { + labels := strings.Split(strings.TrimSuffix(strings.ToLower(hostname), "."), ".") + if len(labels) != 3 && len(labels) != 5 { + return false + } + if labels[2] != "svc" || len(labels) == 5 && (labels[3] != "cluster" || labels[4] != "local") { + return false + } + for _, label := range labels[:2] { + if len(label) == 0 || len(label) > 63 || label[0] == '-' || label[len(label)-1] == '-' { + return false + } + for _, c := range label { + if !(c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '-') { + return false + } + } + } + return true +} diff --git a/libraries/authority-client/go/host/host_test.go b/libraries/authority-client/go/host/host_test.go new file mode 100644 index 00000000..32ee24a9 --- /dev/null +++ b/libraries/authority-client/go/host/host_test.go @@ -0,0 +1,109 @@ +package host + +import ( + "context" + "errors" + "github.com/codefly-dev/core/resources" + "strings" + "testing" +) + +// The host is where authority/endpoint says, over the transport its scheme +// names; with none, the composed local authority's address. +func TestHostTargetReadsTheConfiguredEndpoint(t *testing.T) { + t.Setenv(resources.EnvironmentPrefix, resources.LocalEnvironment().Name) + local := func() (string, error) { return "localhost:7000", nil } + for _, tc := range []struct { + endpoint, target, protocol string + }{ + {"", "localhost:7000", "insecure"}, + {" ", "localhost:7000", "insecure"}, + {"localhost:9000", "localhost:9000", "insecure"}, + {"http://localhost:8080", "localhost:8080", "insecure"}, + {"http://localhost", "localhost:80", "insecure"}, + {"grpc://localhost:9000", "localhost:9000", "insecure"}, + {"https://accounts.example.test", "accounts.example.test:443", "tls"}, + {"https://accounts.example.test:8443/", "accounts.example.test:8443", "tls"}, + } { + target, transport, err := Target(tc.endpoint, local) + if err != nil || target != tc.target || transport.Info().SecurityProtocol != tc.protocol { + t.Errorf("%q: target=%q protocol=%v err=%v; want %q over %s", tc.endpoint, target, transport, err, tc.target, tc.protocol) + } + } +} + +func TestHostTargetRefusesWhatIsNotAnOrigin(t *testing.T) { + local := func() (string, error) { t.Fatal("a configured endpoint never falls back"); return "", nil } + for _, endpoint := range []string{"accounts", "ftp://accounts:21", "https://accounts/v1", "https://u:p@accounts", "http://accounts:1?x=1", "http://"} { + if target, _, err := Target(endpoint, local); err == nil { + t.Errorf("%q was accepted as %q", endpoint, target) + } + } + if _, _, err := Target("", func() (string, error) { return "", errors.New("not resolved") }); err == nil { + t.Error("an unresolved local with no endpoint was accepted") + } +} + +func TestNonLocalPlaintextIsRefused(t *testing.T) { + t.Setenv(resources.EnvironmentPrefix, resources.LocalEnvironment().Name) + for _, target := range []string{"remote.test:8080", "http://remote.test", "grpc://10.0.0.2:443", "tcp://[2001:db8::1]:8080"} { + if _, _, err := Target(target, nil); err == nil { + t.Fatalf("accepted plaintext %s", target) + } + } + if _, _, err := Target("", func() (string, error) { return "remote.test:8080", nil }); err == nil { + t.Fatal("fallback bypassed TLS") + } + for _, target := range []string{"http://127.0.0.1", "http://[::1]"} { + if _, _, err := Target(target, nil); err != nil { + t.Fatal(err) + } + } +} + +func TestMeshProtectedHostUsesCompositionTransport(t *testing.T) { + t.Setenv(resources.EnvironmentPrefix, "production") + for _, assertion := range []string{"", "false", "true", "TRUE", " true", "true "} { + t.Run("assertion="+assertion, func(t *testing.T) { + t.Setenv(resources.WorkspaceConfigurationPrefix+"__INTERNAL_TRANSPORT__MESH_PROTECTED", assertion) + for _, name := range []string{"accounts.platform.svc", "accounts.platform.svc.cluster.local", "accounts.platform.svc.cluster.local.", "10.0.0.2", "remote.test", "localhost", "accounts.platform.svc.evil.test", "accounts..svc", "-accounts.platform.svc", "accounts.plat_form.svc"} { + validName := name == "accounts.platform.svc" || name == "accounts.platform.svc.cluster.local" || name == "accounts.platform.svc.cluster.local." + for _, endpoint := range []string{"http://" + name + ":8080", ""} { + target, transport, err := Target(endpoint, func() (string, error) { return name + ":8080", nil }) + allowed := assertion == "true" && validName + if (err == nil) != allowed { + t.Fatalf("assertion %q host %s fallback %v: %v", assertion, name, endpoint == "", err) + } + if allowed && (target != name+":8080" || transport.Info().SecurityProtocol != "insecure") { + t.Fatalf("unexpected mesh transport %s %v", target, transport) + } + } + } + }) + } +} + +func TestMeshAssertionReadFailureAndMisspellingRefuse(t *testing.T) { + _, err := meshProtected(func(string, string) (string, bool, error) { return "true", true, errors.New("sensitive-value") }) + if err == nil || strings.Contains(err.Error(), "sensitive-value") { + t.Fatalf("unreadable assertion: %v", err) + } + t.Setenv(resources.WorkspaceConfigurationPrefix+"__INTERNAL_TRANSPORT__MESH_PROTECTED", "TRUE") + if _, _, err := Target("https://accounts.example.test", nil); err == nil { + t.Fatal("TLS hid invalid mesh assertion") + } +} + +func TestUpstreamEndpointUsesTheSharedTransportGate(t *testing.T) { + t.Setenv(resources.EnvironmentPrefix, resources.LocalEnvironment().Name) + for _, address := range []string{"http://arbitrary.example:8080", "grpc://192.0.2.1:8080", "", "http://localhost:8080/rewritten"} { + if _, _, err := Endpoint(context.Background(), address); err == nil { + t.Fatalf("accepted upstream %q", address) + } + } + for _, address := range []string{"http://127.0.0.1:8080", "https://upstream.example"} { + if _, _, err := Endpoint(context.Background(), address); err != nil { + t.Fatal(err) + } + } +} diff --git a/libraries/authority-client/go/stamp/context.go b/libraries/authority-client/go/stamp/context.go new file mode 100644 index 00000000..6df35234 --- /dev/null +++ b/libraries/authority-client/go/stamp/context.go @@ -0,0 +1,23 @@ +// Package stamp binds the forwarded Work Context to the trusted hop's proof. +package stamp + +import ( + "crypto/sha256" + "crypto/subtle" + "encoding/hex" + "errors" + "google.golang.org/grpc/metadata" +) + +// Context returns only the token whose digest the authenticated hop stamped. +func Context(md metadata.MD, proof string) (string, error) { + proofs, tokens, digests := md.Get("x-codefly-hop-proof"), md.Get("x-codefly-work-context"), md.Get("x-codefly-hop-context") + if proof == "" || len(proofs) != 1 || subtle.ConstantTimeCompare([]byte(proofs[0]), []byte(proof)) != 1 || len(tokens) != 1 || tokens[0] == "" || len(digests) != 1 { + return "", errors.New("authority: context requires this run's hop proof and a single stamped token") + } + sum := sha256.Sum256([]byte(tokens[0])) + if subtle.ConstantTimeCompare([]byte(hex.EncodeToString(sum[:])), []byte(digests[0])) != 1 { + return "", errors.New("authority: context does not match the hop stamp") + } + return tokens[0], nil +} diff --git a/libraries/authority-client/go/workcontext/claims.go b/libraries/authority-client/go/workcontext/claims.go new file mode 100644 index 00000000..9fccb841 --- /dev/null +++ b/libraries/authority-client/go/workcontext/claims.go @@ -0,0 +1,101 @@ +// Package workcontext projects an already hop-bound Work Context. It is not a +// verifier: readable claims prove neither authentication nor live authority. +package workcontext + +import ( + "encoding/base64" + "errors" + "fmt" + "github.com/codefly-dev/authority/libraries/authority-client/go/stamp" + "google.golang.org/grpc/metadata" + "strings" + + basev0 "github.com/codefly-dev/core/generated/go/codefly/base/v0" + core "github.com/codefly-dev/core/workcontext" + "google.golang.org/protobuf/proto" +) + +// ErrUnreadableContext names a token that cannot be projected. Core's structural +// refusals are also retained in the error chain; no signature is verified. +var ErrUnreadableContext = errors.New("authority: unreadable context") + +// Claims owns a snapshot of the audience and Core's effective scopes. +// It can be read concurrently. Its zero value grants nothing. +type Claims struct { + audience string + scopes []*basev0.WorkScopeV1 +} + +// ReadClaims verifies the hop proof and digest before reading the bound token, using Core's maintained decoder. +// In addition to canonical envelope checks, Go retains Core's structural checks; +// the Python/TypeScript projections do not implement that structural validator. +// None of these readers verifies signatures, time, live revisions or replay. +func ReadClaims(md metadata.MD, proof string) (*Claims, error) { + token, err := stamp.Context(md, proof) + if err != nil { + return nil, fmt.Errorf("%w: %w", ErrUnreadableContext, err) + } + + if len(token) == 0 || len(token) > core.MaxTokenSize { + return nil, fmt.Errorf("%w: expected a bounded context", ErrUnreadableContext) + } + payload, signature, ok := strings.Cut(token, ".") + if !ok || strings.Contains(signature, ".") { + return nil, fmt.Errorf("%w: expected payload.signature", ErrUnreadableContext) + } + for n, segment := range []string{payload, signature} { + decoded, err := base64.RawURLEncoding.DecodeString(segment) + if err != nil || base64.RawURLEncoding.EncodeToString(decoded) != segment || (n == 1 && len(decoded) != 64) { + return nil, fmt.Errorf("%w: noncanonical envelope or invalid signature length", ErrUnreadableContext) + } + } + decoded, err := core.Decode(token) + if err != nil { + return nil, fmt.Errorf("%w: %w", ErrUnreadableContext, err) + } + context := decoded.Context() + scopes := context.GetAuthorityScopes() + if chain := context.GetActorChain(); len(chain) > 0 { + scopes = chain[len(chain)-1].GetGrantedScopes() + } + return &Claims{audience: context.GetAudience(), scopes: scopes}, nil +} + +// Audience is data to compare with this module's delivered audience. +func (c *Claims) Audience() string { + if c == nil { + return "" + } + return c.audience +} + +// Scopes returns deep copies; changing them cannot change later Allows results. +func (c *Claims) Scopes() []*basev0.WorkScopeV1 { + if c == nil { + return nil + } + out := make([]*basev0.WorkScopeV1, len(c.scopes)) + for n, scope := range c.scopes { + out[n] = proto.Clone(scope).(*basev0.WorkScopeV1) + } + return out +} + +// Allows asks for one literal action on one exact resource. An empty resourceID +// asks for the whole kind; a resource-limited grant cannot satisfy that request. +// No wildcard expansion, action implication or cross-grant merging occurs. +func (c *Claims) Allows(kind, action, resourceID string) bool { + if c == nil || kind == "" || action == "" { + return false + } + ask := &basev0.WorkScopeV1{ResourceKind: kind, Actions: []string{action}} + if resourceID != "" { + ask.ResourceIds = []string{resourceID} + } + for _, scope := range c.scopes { + if core.ScopeContained(ask, []*basev0.WorkScopeV1{scope}) { + return true + } + } + return false +} diff --git a/libraries/authority-client/go/workcontext/claims_test.go b/libraries/authority-client/go/workcontext/claims_test.go new file mode 100644 index 00000000..fe3ae465 --- /dev/null +++ b/libraries/authority-client/go/workcontext/claims_test.go @@ -0,0 +1,199 @@ +package workcontext_test + +import ( + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "google.golang.org/grpc/metadata" + "os" + "strings" + "testing" + + reader "github.com/codefly-dev/authority/libraries/authority-client/go/workcontext" + basev0 "github.com/codefly-dev/core/generated/go/codefly/base/v0" + core "github.com/codefly-dev/core/workcontext" + "google.golang.org/protobuf/proto" +) + +type fixture struct { + Name, Token, Audience string + Scopes []*basev0.WorkScopeV1 + Probes []struct { + Kind, Action string + ResourceID string `json:"resource_id"` + Allowed bool + } +} + +func fixtures(t *testing.T) []fixture { + t.Helper() + data, err := os.ReadFile("../../testdata/claims.json") + if err != nil { + t.Fatal(err) + } + var out []fixture + if err := json.Unmarshal(data, &out); err != nil { + t.Fatal(err) + } + return out +} +func body(t *testing.T, name string) *basev0.WorkContextV1 { + t.Helper() + for _, f := range fixtures(t) { + if f.Name == name { + d, err := core.Decode(f.Token) + if err != nil { + t.Fatal(err) + } + return d.Context() + } + } + t.Fatal("fixture missing") + return nil +} + +// Synthetic signatures test projection only; they are not authenticated tokens. +func tokenFor(t *testing.T, c *basev0.WorkContextV1) string { + t.Helper() + b, err := (proto.MarshalOptions{Deterministic: true}).Marshal(c) + if err != nil { + t.Fatal(err) + } + return base64.RawURLEncoding.EncodeToString(b) + "." + base64.RawURLEncoding.EncodeToString(make([]byte, 64)) +} +func read(t *testing.T, c *basev0.WorkContextV1) *reader.Claims { + t.Helper() + out, err := readToken(tokenFor(t, c)) + if err != nil { + t.Fatal(err) + } + return out +} +func TestCoreFixtures(t *testing.T) { + for _, f := range fixtures(t) { + t.Run(f.Name, func(t *testing.T) { + c, err := readToken(f.Token) + if err != nil { + t.Fatal(err) + } + if c.Audience() != f.Audience { + t.Fatal("audience differs") + } + scopes := c.Scopes() + if len(scopes) != len(f.Scopes) { + t.Fatal("effective scope count differs") + } + for n, scope := range scopes { + if !proto.Equal(scope, f.Scopes[n]) { + t.Fatalf("scope %d differs", n) + } + } + for _, p := range f.Probes { + if c.Allows(p.Kind, p.Action, p.ResourceID) != p.Allowed { + t.Fatalf("probe %s %s %s", p.Kind, p.Action, p.ResourceID) + } + } + }) + } +} +func TestSeparateGrantsAndWholeKind(t *testing.T) { + c := body(t, "session") + c.AuthorityScopes = []*basev0.WorkScopeV1{ + {ResourceKind: "record", Actions: []string{"read"}, ResourceIds: []string{"a"}}, + {ResourceKind: "record", Actions: []string{"invoke"}, ResourceIds: []string{"b"}}, + } + claims := read(t, c) + for _, q := range []struct { + action, id string + allowed bool + }{{"read", "a", true}, {"invoke", "b", true}, {"invoke", "a", false}, {"read", "b", false}, {"read", "", false}} { + if claims.Allows("record", q.action, q.id) != q.allowed { + t.Fatal(q) + } + } + copied := claims.Scopes() + copied[0].Actions = append(copied[0].Actions, "invoke") + copied[0].ResourceIds = append(copied[0].ResourceIds, "b") + if claims.Allows("record", "invoke", "a") { + t.Fatal("mutable scope escaped") + } + c.AuthorityScopes = []*basev0.WorkScopeV1{{ResourceKind: "record", Actions: []string{"read", "admin", "*"}}} + claims = read(t, c) + if !claims.Allows("record", "read", "") || !claims.Allows("record", "read", "a") || claims.Allows("record", "invoke", "a") || claims.Allows("", "read", "") || claims.Allows("record", "", "") { + t.Fatal("literal scope semantics changed") + } + var empty reader.Claims + if empty.Allows("record", "read", "") { + t.Fatal("zero claims grant authority") + } +} +func TestEmptyFinalActorGrantsNothing(t *testing.T) { + c := body(t, "delegated") + c.ActorChain[len(c.ActorChain)-1].GrantedScopes = nil + claims := read(t, c) + if len(claims.Scopes()) != 0 || claims.Allows("record", "read", "record-conformance") { + t.Fatal("earlier scopes leaked") + } +} +func TestUnreadableContexts(t *testing.T) { + valid := tokenFor(t, body(t, "session")) + payload, _, _ := strings.Cut(valid, ".") + for _, token := range []string{"", "abc", "a.b.c", ".", "é.x", strings.Repeat("a", 32*1024+1), valid + "=", payload + ".AA", payload + "." + strings.Repeat("A", 85) + "B"} { + if _, err := readToken(token); !errors.Is(err, reader.ErrUnreadableContext) { + t.Fatalf("envelope not refused: %v", err) + } + } + for _, where := range []string{"root", "nested", "duplicate", "audience", "structural"} { + t.Run(where, func(t *testing.T) { + c := body(t, "session") + switch where { + case "root": + c.ProtoReflect().SetUnknown([]byte{0xf8, 0x07, 0x01}) + case "nested": + c.AuthorityScopes[0].ProtoReflect().SetUnknown([]byte{0x78, 0x01}) + case "audience": + c.Audience = "" + case "structural": + c.Seal = nil + } + token := tokenFor(t, c) + if where == "duplicate" { + p, s, _ := strings.Cut(token, ".") + b, _ := base64.RawURLEncoding.DecodeString(p) + token = base64.RawURLEncoding.EncodeToString(append(b, b...)) + "." + s + } + if _, err := readToken(token); !errors.Is(err, reader.ErrUnreadableContext) { + t.Fatalf("malformed claims not refused: %v", err) + } + }) + } +} + +func stampedToken(token string) metadata.MD { + sum := sha256.Sum256([]byte(token)) + return metadata.Pairs("x-codefly-work-context", token, "x-codefly-hop-proof", "test-proof", "x-codefly-hop-context", hex.EncodeToString(sum[:])) +} +func readToken(token string) (*reader.Claims, error) { + return reader.ReadClaims(stampedToken(token), "test-proof") +} +func TestReadClaimsRequiresTheStamp(t *testing.T) { + token := fixtures(t)[0].Token + for _, change := range []func(metadata.MD){ + func(md metadata.MD) { md.Delete("x-codefly-hop-proof") }, + func(md metadata.MD) { md.Set("x-codefly-hop-proof", "forged") }, + func(md metadata.MD) { md.Delete("x-codefly-hop-context") }, + func(md metadata.MD) { md.Set("x-codefly-work-context", token+"forged") }, + func(md metadata.MD) { md.Append("x-codefly-work-context", token) }, + } { + md := stampedToken(token) + change(md) + if _, err := reader.ReadClaims(md, "test-proof"); !errors.Is(err, reader.ErrUnreadableContext) { + t.Fatalf("unbound claims accepted: %v", err) + } + } + if _, err := reader.ReadClaims(stampedToken(token), ""); err == nil { + t.Fatal("empty proof accepted") + } +} diff --git a/libraries/authority-client/library.codefly.yaml b/libraries/authority-client/library.codefly.yaml index 0fe106c3..1af6d794 100644 --- a/libraries/authority-client/library.codefly.yaml +++ b/libraries/authority-client/library.codefly.yaml @@ -10,13 +10,17 @@ languages: path: python/ exports: - authority_client + - name: typescript + path: typescript/ + exports: + - '@codefly-dev/authority-client' sources: - package: local version: 0.0.0 module: authority - service: gateway + service: local endpoint: grpc - contract-digest: sha256:89baa9ae5c5f7940f17b303afdb58824e913427d3fb826c81b24f78e5378d599 + contract-digest: sha256:d2fcb57f3608ea6c57918565db2d83cc69d7e9cebee33edadf2160a3fee8d635 services: - GatewayService generated-by: diff --git a/libraries/authority-client/python/README.md b/libraries/authority-client/python/README.md new file mode 100644 index 00000000..b320dbf7 --- /dev/null +++ b/libraries/authority-client/python/README.md @@ -0,0 +1,52 @@ +# Authority Python client + +The Codefly-generated authority bindings are accompanied by a small, non-verifying +Work Context reader. The reader verifies the incoming hop stamp itself before projecting the bound +context through the generated protobuf type: + +```python +from authority_client.work_context import read_claims + +claims = read_claims(request.headers, proof) +# Compare claims.audience to this module's delivered audience. +allowed = claims.allows(resource_kind, action, installed_resource_id) +``` + +The reader preserves Core's effective scopes: the final actor's grants, or the +owner's grants when there is no actor. An empty final grant stays empty. Each +scope is evaluated independently, so an action on one resource is not combined +with an unrelated resource from another scope. An omitted resource ID asks for +whole-kind authority; a resource-limited grant cannot satisfy it. A whole-kind +grant can satisfy a named-resource request. Actions are literal, following the +existing Core containment rule and Python SDK; `admin` implies no other action, +and raw token `*` actions are not expanded here. + +`read_claims` raises `UnreadableContext` for a missing/forged stamp, a substituted token, an unreadable envelope, unknown wire +fields, noncanonical payload or absent audience. It does **not** replace Core's +structural validation, authenticate a signature, check time/revocation or consume +a replay nonce. In warning mode even a stamped context may have been refused by +the authority. The advisory is diagnostic and grants nothing. Keep the module's +installed-definition, audience, expiry, ownership and visibility checks. Resolve +resource IDs from the domain object; never use a kind-wide fallback when a bound +context is missing or unreadable. + +This package directly reuses its generated `WorkContextV1` binding. Its canonical +wire and exact-resource checks follow the existing Python SDK's algorithms; +they are maintained here during migration, not imported from its private helpers. +SDK changes therefore require an explicit parity review until it adopts this seam. +It does not depend on a running SaaS service or introduce another verifier. + +Pin consumers by repository commit, together with the hop package: +`authority-client @ git+https://github.com/codefly-dev/authority@#subdirectory=libraries/authority-client/python`. + +Run the Python tests from this directory: + +```sh +uv run --no-project --with pytest --with-editable . pytest tests +``` + +The shared `../testdata/claims.json` contains Core-minted tokens and effective +scope/query expectations. The gateway's `TestPythonClaimProjectionFixtures` +verifies them against Core with a fixed test clock; use its +`-update-python-claims` flag to regenerate. These public conformance tokens are +test data, never credentials for a running installation. diff --git a/libraries/authority-client/python/authority_client/_gen/api_pb2.py b/libraries/authority-client/python/authority_client/_gen/api_pb2.py index 676aa04f..6b8100b2 100644 --- a/libraries/authority-client/python/authority_client/_gen/api_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/api_pb2.py @@ -24,13 +24,14 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tapi.proto\x12\x03\x61pi\"\x10\n\x0eVersionRequest\"+\n\x0fVersionResponse\x12\x18\n\x07version\x18\x01 \x01(\tR\x07version2F\n\x0eGatewayService\x12\x34\n\x07Version\x12\x13.api.VersionRequest\x1a\x14.api.VersionResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tapi.proto\x12\x03\x61pi\"\x10\n\x0eVersionRequest\"+\n\x0fVersionResponse\x12\x18\n\x07version\x18\x01 \x01(\tR\x07version2F\n\x0eGatewayService\x12\x34\n\x07Version\x12\x13.api.VersionRequest\x1a\x14.api.VersionResponseB\x15Z\x13gateway/pkg/gen;genb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'api_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z\023gateway/pkg/gen;gen' _globals['_VERSIONREQUEST']._serialized_start=18 _globals['_VERSIONREQUEST']._serialized_end=34 _globals['_VERSIONRESPONSE']._serialized_start=36 diff --git a/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2.py b/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2.py index 15f190f8..a3026296 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2.py @@ -24,13 +24,14 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fhost/artifact/v1/artifact.proto\x12\x10host.artifact.v1\"J\n\x08\x43ontract\x12\x12\n\x04kind\x18\x01 \x01(\tR\x04kind\x12\x12\n\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n\x06\x64igest\x18\x03 \x01(\tR\x06\x64igest\"\xbb\x01\n\x08Identity\x12\x16\n\x06schema\x18\x01 \x01(\tR\x06schema\x12\x16\n\x06source\x18\x02 \x01(\tR\x06source\x12\x18\n\x07subject\x18\x03 \x01(\x0cR\x07subject\x12\x38\n\tcontracts\x18\x04 \x03(\x0b\x32\x1a.host.artifact.v1.ContractR\tcontracts\x12+\n\x11\x65xpected_revision\x18\x05 \x01(\x03R\x10\x65xpectedRevision\"\xd8\x01\n\x0f\x41rtifactRequest\x12!\n\x0cparent_token\x18\x01 \x01(\tR\x0bparentToken\x12)\n\x10\x61\x63tor_credential\x18\x02 \x01(\tR\x0f\x61\x63torCredential\x12\'\n\x0finstallation_id\x18\x03 \x01(\tR\x0einstallationId\x12\x16\n\x06policy\x18\x04 \x01(\tR\x06policy\x12\x36\n\x08identity\x18\x05 \x01(\x0b\x32\x1a.host.artifact.v1.IdentityR\x08identity\"\xbf\x01\n\rRevokeRequest\x12!\n\x0cparent_token\x18\x01 \x01(\tR\x0bparentToken\x12)\n\x10\x61\x63tor_credential\x18\x02 \x01(\tR\x0f\x61\x63torCredential\x12\'\n\x0finstallation_id\x18\x03 \x01(\tR\x0einstallationId\x12\x16\n\x06policy\x18\x04 \x01(\tR\x06policy\x12\x1f\n\x0b\x61pproval_id\x18\x05 \x01(\tR\napprovalId\"v\n\x08\x41pproval\x12%\n\x0equalified_name\x18\x01 \x01(\tR\rqualifiedName\x12\x16\n\x06\x64igest\x18\x02 \x01(\tR\x06\x64igest\x12+\n\x11\x65xpected_revision\x18\x03 \x01(\x03R\x10\x65xpectedRevision2\xee\x01\n\x0f\x41rtifactService\x12H\n\x07\x41pprove\x12!.host.artifact.v1.ArtifactRequest\x1a\x1a.host.artifact.v1.Approval\x12J\n\tAuthorize\x12!.host.artifact.v1.ArtifactRequest\x1a\x1a.host.artifact.v1.Approval\x12\x45\n\x06Revoke\x12\x1f.host.artifact.v1.RevokeRequest\x1a\x1a.host.artifact.v1.Approvalb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fhost/artifact/v1/artifact.proto\x12\x10host.artifact.v1\"J\n\x08\x43ontract\x12\x12\n\x04kind\x18\x01 \x01(\tR\x04kind\x12\x12\n\x04name\x18\x02 \x01(\tR\x04name\x12\x16\n\x06\x64igest\x18\x03 \x01(\tR\x06\x64igest\"\xbb\x01\n\x08Identity\x12\x16\n\x06schema\x18\x01 \x01(\tR\x06schema\x12\x16\n\x06source\x18\x02 \x01(\tR\x06source\x12\x18\n\x07subject\x18\x03 \x01(\x0cR\x07subject\x12\x38\n\tcontracts\x18\x04 \x03(\x0b\x32\x1a.host.artifact.v1.ContractR\tcontracts\x12+\n\x11\x65xpected_revision\x18\x05 \x01(\x03R\x10\x65xpectedRevision\"\xd8\x01\n\x0f\x41rtifactRequest\x12!\n\x0cparent_token\x18\x01 \x01(\tR\x0bparentToken\x12)\n\x10\x61\x63tor_credential\x18\x02 \x01(\tR\x0f\x61\x63torCredential\x12\'\n\x0finstallation_id\x18\x03 \x01(\tR\x0einstallationId\x12\x16\n\x06policy\x18\x04 \x01(\tR\x06policy\x12\x36\n\x08identity\x18\x05 \x01(\x0b\x32\x1a.host.artifact.v1.IdentityR\x08identity\"\xbf\x01\n\rRevokeRequest\x12!\n\x0cparent_token\x18\x01 \x01(\tR\x0bparentToken\x12)\n\x10\x61\x63tor_credential\x18\x02 \x01(\tR\x0f\x61\x63torCredential\x12\'\n\x0finstallation_id\x18\x03 \x01(\tR\x0einstallationId\x12\x16\n\x06policy\x18\x04 \x01(\tR\x06policy\x12\x1f\n\x0b\x61pproval_id\x18\x05 \x01(\tR\napprovalId\"v\n\x08\x41pproval\x12%\n\x0equalified_name\x18\x01 \x01(\tR\rqualifiedName\x12\x16\n\x06\x64igest\x18\x02 \x01(\tR\x06\x64igest\x12+\n\x11\x65xpected_revision\x18\x03 \x01(\x03R\x10\x65xpectedRevision2\xee\x01\n\x0f\x41rtifactService\x12H\n\x07\x41pprove\x12!.host.artifact.v1.ArtifactRequest\x1a\x1a.host.artifact.v1.Approval\x12J\n\tAuthorize\x12!.host.artifact.v1.ArtifactRequest\x1a\x1a.host.artifact.v1.Approval\x12\x45\n\x06Revoke\x12\x1f.host.artifact.v1.RevokeRequest\x1a\x1a.host.artifact.v1.ApprovalB-Z+gateway/pkg/gen/host/artifact/v1;artifactv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'host.artifact.v1.artifact_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z+gateway/pkg/gen/host/artifact/v1;artifactv1' _globals['_CONTRACT']._serialized_start=53 _globals['_CONTRACT']._serialized_end=127 _globals['_IDENTITY']._serialized_start=130 diff --git a/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2_grpc.py b/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2_grpc.py index ff2f78aa..4fa5c5d2 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2_grpc.py +++ b/libraries/authority-client/python/authority_client/_gen/host/artifact/v1/artifact_pb2_grpc.py @@ -26,7 +26,7 @@ class ArtifactServiceStub(object): - """ArtifactService is implemented by the host and by the authority gateway. + """ArtifactService is implemented by the host and by the local authority. """ def __init__(self, channel): @@ -53,7 +53,7 @@ def __init__(self, channel): class ArtifactServiceServicer(object): - """ArtifactService is implemented by the host and by the authority gateway. + """ArtifactService is implemented by the host and by the local authority. """ def Approve(self, request, context): @@ -113,7 +113,7 @@ def add_ArtifactServiceServicer_to_server(servicer, server): # This class is part of an EXPERIMENTAL API. class ArtifactService(object): - """ArtifactService is implemented by the host and by the authority gateway. + """ArtifactService is implemented by the host and by the local authority. """ @staticmethod diff --git a/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2.py b/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2.py index 0d05a98f..c5c2585e 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2.py @@ -25,13 +25,14 @@ from authority_client._gen.host.authority.v1 import work_context_pb2 as host_dot_authority_dot_v1_dot_work__context__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!host/authority/v1/authority.proto\x12\x11host.authority.v1\x1a$host/authority/v1/work_context.proto\"\xf3\x04\n\x0cIssueRequest\x12:\n\x06person\x18\x01 \x01(\x0b\x32 .host.authority.v1.PersonSessionH\x00R\x06person\x12\x43\n\x08workload\x18\x02 \x01(\x0b\x32%.host.authority.v1.WorkloadCredentialH\x00R\x08workload\x12H\n\x0cinstallation\x18\x03 \x01(\x0b\x32\".host.authority.v1.InstallationRefH\x00R\x0cinstallation\x12#\n\x0cparent_token\x18\x04 \x01(\tH\x00R\x0bparentToken\x12\x42\n\ndelegation\x18\x0b \x01(\x0b\x32 .host.authority.v1.DelegationRefH\x00R\ndelegation\x12\x1a\n\x08\x61udience\x18\x05 \x01(\tR\x08\x61udience\x12\x36\n\x06scopes\x18\x06 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\x12\x1f\n\x0bttl_seconds\x18\x07 \x01(\x03R\nttlSeconds\x12\x30\n\x14operation_binding_id\x18\x08 \x01(\tR\x12operationBindingId\x12\'\n\x0forganization_id\x18\t \x01(\tR\x0eorganizationId\x12;\n\x05\x61\x63tor\x18\n \x01(\x0b\x32%.host.authority.v1.WorkloadCredentialR\x05\x61\x63tor\x12\x1c\n\toperation\x18\x0c \x01(\tR\toperationB\x04\n\x02\x61s\"4\n\rDelegationRef\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\"{\n\x0f\x44\x65legateRequest\x12\x16\n\x06module\x18\x01 \x01(\tR\x06module\x12\x36\n\x06scopes\x18\x02 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\x12\x18\n\x07purpose\x18\x03 \x01(\tR\x07purpose\"\xf6\x01\n\nDelegation\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\x12\'\n\x0forganization_id\x18\x02 \x01(\tR\x0eorganizationId\x12\x18\n\x07grantor\x18\x03 \x01(\tR\x07grantor\x12\x16\n\x06module\x18\x04 \x01(\tR\x06module\x12\x36\n\x06scopes\x18\x05 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\x12\x18\n\x07purpose\x18\x06 \x01(\tR\x07purpose\x12\x16\n\x06\x61\x63tive\x18\x07 \x01(\x08R\x06\x61\x63tive\"x\n\x14GetDelegationRequest\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\x12;\n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32%.host.authority.v1.WorkloadCredentialR\x05\x61\x63tor\">\n\x17RevokeDelegationRequest\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\"Y\n\x18RevokeDelegationResponse\x12=\n\ndelegation\x18\x01 \x01(\x0b\x32\x1d.host.authority.v1.DelegationR\ndelegation\"!\n\rPersonSessionJ\x04\x08\x01\x10\x02R\nsession_id\"4\n\x12WorkloadCredential\x12\x1e\n\ncredential\x18\x01 \x01(\tR\ncredential\":\n\x0fInstallationRef\x12\'\n\x0finstallation_id\x18\x01 \x01(\tR\x0einstallationId\"\x89\x01\n\rIssueResponse\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12&\n\x0f\x65xpires_at_unix\x18\x02 \x01(\x03R\rexpiresAtUnix\x12:\n\x07\x63ontext\x18\x03 \x01(\x0b\x32 .host.authority.v1.WorkContextV1R\x07\x63ontext\"X\n\x0c\x43heckRequest\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12\x1a\n\x08\x61udience\x18\x02 \x01(\tR\x08\x61udience\x12\x16\n\x06method\x18\x03 \x01(\tR\x06method\"\x82\x01\n\rCheckResponse\x12:\n\x07\x63ontext\x18\x01 \x01(\x0b\x32 .host.authority.v1.WorkContextV1R\x07\x63ontext\x12\x35\n\x16\x61uthorization_revision\x18\x02 \x01(\x04R\x15\x61uthorizationRevision\"\r\n\x0bKeysRequest\"X\n\x0cKeysResponse\x12\x16\n\x06issuer\x18\x01 \x01(\tR\x06issuer\x12\x30\n\x04keys\x18\x02 \x03(\x0b\x32\x1c.host.authority.v1.PublicKeyR\x04keys\"_\n\tPublicKey\x12\x15\n\x06key_id\x18\x01 \x01(\tR\x05keyId\x12\x1c\n\talgorithm\x18\x02 \x01(\tR\talgorithm\x12\x1d\n\npublic_key\x18\x03 \x01(\x0cR\tpublicKey\"\x85\x01\n\x14ListResourcesRequest\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12\x1a\n\x08\x61udience\x18\x02 \x01(\tR\x08\x61udience\x12#\n\rresource_kind\x18\x03 \x01(\tR\x0cresourceKind\x12\x16\n\x06\x61\x63tion\x18\x04 \x01(\tR\x06\x61\x63tion\"Q\n\x15ListResourcesResponse\x12\x38\n\x06grants\x18\x01 \x03(\x0b\x32 .host.authority.v1.ResourceGrantR\x06grants\"t\n\rResourceGrant\x12\x12\n\x03\x61ll\x18\x01 \x01(\x08H\x00R\x03\x61ll\x12\x10\n\x02id\x18\x02 \x01(\tH\x00R\x02id\x12\x18\n\x06prefix\x18\x03 \x01(\tH\x00R\x06prefix\x12\x1a\n\x07pattern\x18\x04 \x01(\tH\x00R\x07patternB\x07\n\x05match2\xec\x04\n\x10\x41uthorityService\x12J\n\x05Issue\x12\x1f.host.authority.v1.IssueRequest\x1a .host.authority.v1.IssueResponse\x12J\n\x05\x43heck\x12\x1f.host.authority.v1.CheckRequest\x1a .host.authority.v1.CheckResponse\x12G\n\x04Keys\x12\x1e.host.authority.v1.KeysRequest\x1a\x1f.host.authority.v1.KeysResponse\x12\x62\n\rListResources\x12\'.host.authority.v1.ListResourcesRequest\x1a(.host.authority.v1.ListResourcesResponse\x12M\n\x08\x44\x65legate\x12\".host.authority.v1.DelegateRequest\x1a\x1d.host.authority.v1.Delegation\x12k\n\x10RevokeDelegation\x12*.host.authority.v1.RevokeDelegationRequest\x1a+.host.authority.v1.RevokeDelegationResponse\x12W\n\rGetDelegation\x12\'.host.authority.v1.GetDelegationRequest\x1a\x1d.host.authority.v1.Delegationb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!host/authority/v1/authority.proto\x12\x11host.authority.v1\x1a$host/authority/v1/work_context.proto\"\xf3\x04\n\x0cIssueRequest\x12:\n\x06person\x18\x01 \x01(\x0b\x32 .host.authority.v1.PersonSessionH\x00R\x06person\x12\x43\n\x08workload\x18\x02 \x01(\x0b\x32%.host.authority.v1.WorkloadCredentialH\x00R\x08workload\x12H\n\x0cinstallation\x18\x03 \x01(\x0b\x32\".host.authority.v1.InstallationRefH\x00R\x0cinstallation\x12#\n\x0cparent_token\x18\x04 \x01(\tH\x00R\x0bparentToken\x12\x42\n\ndelegation\x18\x0b \x01(\x0b\x32 .host.authority.v1.DelegationRefH\x00R\ndelegation\x12\x1a\n\x08\x61udience\x18\x05 \x01(\tR\x08\x61udience\x12\x36\n\x06scopes\x18\x06 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\x12\x1f\n\x0bttl_seconds\x18\x07 \x01(\x03R\nttlSeconds\x12\x30\n\x14operation_binding_id\x18\x08 \x01(\tR\x12operationBindingId\x12\'\n\x0forganization_id\x18\t \x01(\tR\x0eorganizationId\x12;\n\x05\x61\x63tor\x18\n \x01(\x0b\x32%.host.authority.v1.WorkloadCredentialR\x05\x61\x63tor\x12\x1c\n\toperation\x18\x0c \x01(\tR\toperationB\x04\n\x02\x61s\"4\n\rDelegationRef\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\"{\n\x0f\x44\x65legateRequest\x12\x16\n\x06module\x18\x01 \x01(\tR\x06module\x12\x36\n\x06scopes\x18\x02 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\x12\x18\n\x07purpose\x18\x03 \x01(\tR\x07purpose\"\xf6\x01\n\nDelegation\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\x12\'\n\x0forganization_id\x18\x02 \x01(\tR\x0eorganizationId\x12\x18\n\x07grantor\x18\x03 \x01(\tR\x07grantor\x12\x16\n\x06module\x18\x04 \x01(\tR\x06module\x12\x36\n\x06scopes\x18\x05 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\x12\x18\n\x07purpose\x18\x06 \x01(\tR\x07purpose\x12\x16\n\x06\x61\x63tive\x18\x07 \x01(\x08R\x06\x61\x63tive\"x\n\x14GetDelegationRequest\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\x12;\n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32%.host.authority.v1.WorkloadCredentialR\x05\x61\x63tor\">\n\x17RevokeDelegationRequest\x12#\n\rdelegation_id\x18\x01 \x01(\tR\x0c\x64\x65legationId\"Y\n\x18RevokeDelegationResponse\x12=\n\ndelegation\x18\x01 \x01(\x0b\x32\x1d.host.authority.v1.DelegationR\ndelegation\"!\n\rPersonSessionJ\x04\x08\x01\x10\x02R\nsession_id\"4\n\x12WorkloadCredential\x12\x1e\n\ncredential\x18\x01 \x01(\tR\ncredential\":\n\x0fInstallationRef\x12\'\n\x0finstallation_id\x18\x01 \x01(\tR\x0einstallationId\"\x89\x01\n\rIssueResponse\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12&\n\x0f\x65xpires_at_unix\x18\x02 \x01(\x03R\rexpiresAtUnix\x12:\n\x07\x63ontext\x18\x03 \x01(\x0b\x32 .host.authority.v1.WorkContextV1R\x07\x63ontext\"t\n\x0c\x43heckRequest\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12\x1a\n\x08\x61udience\x18\x02 \x01(\tR\x08\x61udience\x12\x16\n\x06method\x18\x03 \x01(\tR\x06method\x12\x1a\n\x08\x61\x64visory\x18\x04 \x01(\x08R\x08\x61\x64visory\"\x9c\x01\n\rCheckResponse\x12:\n\x07\x63ontext\x18\x01 \x01(\x0b\x32 .host.authority.v1.WorkContextV1R\x07\x63ontext\x12\x35\n\x16\x61uthorization_revision\x18\x02 \x01(\x04R\x15\x61uthorizationRevision\x12\x18\n\x07refusal\x18\x03 \x01(\tR\x07refusal\"\r\n\x0bKeysRequest\"X\n\x0cKeysResponse\x12\x16\n\x06issuer\x18\x01 \x01(\tR\x06issuer\x12\x30\n\x04keys\x18\x02 \x03(\x0b\x32\x1c.host.authority.v1.PublicKeyR\x04keys\"_\n\tPublicKey\x12\x15\n\x06key_id\x18\x01 \x01(\tR\x05keyId\x12\x1c\n\talgorithm\x18\x02 \x01(\tR\talgorithm\x12\x1d\n\npublic_key\x18\x03 \x01(\x0cR\tpublicKey\"\x85\x01\n\x14ListResourcesRequest\x12\x14\n\x05token\x18\x01 \x01(\tR\x05token\x12\x1a\n\x08\x61udience\x18\x02 \x01(\tR\x08\x61udience\x12#\n\rresource_kind\x18\x03 \x01(\tR\x0cresourceKind\x12\x16\n\x06\x61\x63tion\x18\x04 \x01(\tR\x06\x61\x63tion\"Q\n\x15ListResourcesResponse\x12\x38\n\x06grants\x18\x01 \x03(\x0b\x32 .host.authority.v1.ResourceGrantR\x06grants\"t\n\rResourceGrant\x12\x12\n\x03\x61ll\x18\x01 \x01(\x08H\x00R\x03\x61ll\x12\x10\n\x02id\x18\x02 \x01(\tH\x00R\x02id\x12\x18\n\x06prefix\x18\x03 \x01(\tH\x00R\x06prefix\x12\x1a\n\x07pattern\x18\x04 \x01(\tH\x00R\x07patternB\x07\n\x05match2\xec\x04\n\x10\x41uthorityService\x12J\n\x05Issue\x12\x1f.host.authority.v1.IssueRequest\x1a .host.authority.v1.IssueResponse\x12J\n\x05\x43heck\x12\x1f.host.authority.v1.CheckRequest\x1a .host.authority.v1.CheckResponse\x12G\n\x04Keys\x12\x1e.host.authority.v1.KeysRequest\x1a\x1f.host.authority.v1.KeysResponse\x12\x62\n\rListResources\x12\'.host.authority.v1.ListResourcesRequest\x1a(.host.authority.v1.ListResourcesResponse\x12M\n\x08\x44\x65legate\x12\".host.authority.v1.DelegateRequest\x1a\x1d.host.authority.v1.Delegation\x12k\n\x10RevokeDelegation\x12*.host.authority.v1.RevokeDelegationRequest\x1a+.host.authority.v1.RevokeDelegationResponse\x12W\n\rGetDelegation\x12\'.host.authority.v1.GetDelegationRequest\x1a\x1d.host.authority.v1.DelegationB/Z-gateway/pkg/gen/host/authority/v1;authorityv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'host.authority.v1.authority_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z-gateway/pkg/gen/host/authority/v1;authorityv1' _globals['_ISSUEREQUEST']._serialized_start=95 _globals['_ISSUEREQUEST']._serialized_end=722 _globals['_DELEGATIONREF']._serialized_start=724 @@ -55,21 +56,21 @@ _globals['_ISSUERESPONSE']._serialized_start=1579 _globals['_ISSUERESPONSE']._serialized_end=1716 _globals['_CHECKREQUEST']._serialized_start=1718 - _globals['_CHECKREQUEST']._serialized_end=1806 - _globals['_CHECKRESPONSE']._serialized_start=1809 - _globals['_CHECKRESPONSE']._serialized_end=1939 - _globals['_KEYSREQUEST']._serialized_start=1941 - _globals['_KEYSREQUEST']._serialized_end=1954 - _globals['_KEYSRESPONSE']._serialized_start=1956 - _globals['_KEYSRESPONSE']._serialized_end=2044 - _globals['_PUBLICKEY']._serialized_start=2046 - _globals['_PUBLICKEY']._serialized_end=2141 - _globals['_LISTRESOURCESREQUEST']._serialized_start=2144 - _globals['_LISTRESOURCESREQUEST']._serialized_end=2277 - _globals['_LISTRESOURCESRESPONSE']._serialized_start=2279 - _globals['_LISTRESOURCESRESPONSE']._serialized_end=2360 - _globals['_RESOURCEGRANT']._serialized_start=2362 - _globals['_RESOURCEGRANT']._serialized_end=2478 - _globals['_AUTHORITYSERVICE']._serialized_start=2481 - _globals['_AUTHORITYSERVICE']._serialized_end=3101 + _globals['_CHECKREQUEST']._serialized_end=1834 + _globals['_CHECKRESPONSE']._serialized_start=1837 + _globals['_CHECKRESPONSE']._serialized_end=1993 + _globals['_KEYSREQUEST']._serialized_start=1995 + _globals['_KEYSREQUEST']._serialized_end=2008 + _globals['_KEYSRESPONSE']._serialized_start=2010 + _globals['_KEYSRESPONSE']._serialized_end=2098 + _globals['_PUBLICKEY']._serialized_start=2100 + _globals['_PUBLICKEY']._serialized_end=2195 + _globals['_LISTRESOURCESREQUEST']._serialized_start=2198 + _globals['_LISTRESOURCESREQUEST']._serialized_end=2331 + _globals['_LISTRESOURCESRESPONSE']._serialized_start=2333 + _globals['_LISTRESOURCESRESPONSE']._serialized_end=2414 + _globals['_RESOURCEGRANT']._serialized_start=2416 + _globals['_RESOURCEGRANT']._serialized_end=2532 + _globals['_AUTHORITYSERVICE']._serialized_start=2535 + _globals['_AUTHORITYSERVICE']._serialized_end=3155 # @@protoc_insertion_point(module_scope) diff --git a/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2_grpc.py b/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2_grpc.py index 9f189a0a..43cd9d78 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2_grpc.py +++ b/libraries/authority-client/python/authority_client/_gen/host/authority/v1/authority_pb2_grpc.py @@ -26,7 +26,7 @@ class AuthorityServiceStub(object): - """AuthorityService is implemented by the host (accounts) and by the authority gateway. + """AuthorityService is implemented by the host (accounts) and by the local authority. """ def __init__(self, channel): @@ -73,7 +73,7 @@ def __init__(self, channel): class AuthorityServiceServicer(object): - """AuthorityService is implemented by the host (accounts) and by the authority gateway. + """AuthorityService is implemented by the host (accounts) and by the local authority. """ def Issue(self, request, context): @@ -184,7 +184,7 @@ def add_AuthorityServiceServicer_to_server(servicer, server): # This class is part of an EXPERIMENTAL API. class AuthorityService(object): - """AuthorityService is implemented by the host (accounts) and by the authority gateway. + """AuthorityService is implemented by the host (accounts) and by the local authority. """ @staticmethod diff --git a/libraries/authority-client/python/authority_client/_gen/host/authority/v1/work_context_pb2.py b/libraries/authority-client/python/authority_client/_gen/host/authority/v1/work_context_pb2.py index e721fe9c..f494f35a 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/authority/v1/work_context_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/host/authority/v1/work_context_pb2.py @@ -24,13 +24,14 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$host/authority/v1/work_context.proto\x12\x11host.authority.v1\"\xaf\n\n\rWorkContextV1\x12\x10\n\x03typ\x18\x01 \x01(\tR\x03typ\x12\x1c\n\talgorithm\x18\x02 \x01(\tR\talgorithm\x12\x15\n\x06key_id\x18\x03 \x01(\tR\x05keyId\x12\x16\n\x06issuer\x18\x04 \x01(\tR\x06issuer\x12\x1a\n\x08\x61udience\x18\x05 \x01(\tR\x08\x61udience\x12&\n\x0fnot_before_unix\x18\x06 \x01(\x03R\rnotBeforeUnix\x12$\n\x0eissued_at_unix\x18\x07 \x01(\x03R\x0cissuedAtUnix\x12&\n\x0f\x65xpires_at_unix\x18\x08 \x01(\x03R\rexpiresAtUnix\x12\x14\n\x05nonce\x18\t \x01(\tR\x05nonce\x12\x35\n\x16\x61uthorization_revision\x18\n \x01(\x04R\x15\x61uthorizationRevision\x12#\n\rreplay_policy\x18\x0b \x01(\tR\x0creplayPolicy\x12\x1b\n\ttenant_id\x18\x0c \x01(\tR\x08tenantId\x12,\n\x12owner_principal_id\x18\r \x01(\tR\x10ownerPrincipalId\x12\x17\n\x07task_id\x18\x0e \x01(\tR\x06taskId\x12\x1d\n\nsession_id\x18\x0f \x01(\tR\tsessionId\x12/\n\x11parent_session_id\x18\x10 \x01(\tH\x00R\x0fparentSessionId\x88\x01\x01\x12I\n\x10\x61uthority_scopes\x18\x11 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0f\x61uthorityScopes\x12?\n\x0b\x61\x63tor_chain\x18\x12 \x03(\x0b\x32\x1e.host.authority.v1.WorkActorV1R\nactorChain\x12\x30\n\x14\x61ttribution_team_ids\x18\x13 \x03(\tR\x12\x61ttributionTeamIds\x12&\n\x0cworkspace_id\x18\x14 \x01(\tH\x01R\x0bworkspaceId\x88\x01\x01\x12\"\n\nproject_id\x18\x15 \x01(\tH\x02R\tprojectId\x88\x01\x01\x12\x35\n\x14owner_principal_kind\x18\x16 \x01(\tH\x03R\x12ownerPrincipalKind\x88\x01\x01\x12)\n\x0eowner_agent_id\x18\x17 \x01(\tH\x04R\x0cownerAgentId\x88\x01\x01\x12,\n\x0forganization_id\x18\x19 \x01(\tH\x05R\x0eorganizationId\x88\x01\x01\x12\x43\n\tgrant_hop\x18\x18 \x01(\x0b\x32!.host.authority.v1.WorkGrantHopV1H\x06R\x08grantHop\x88\x01\x01\x12\x31\n\x04seal\x18\x1a \x01(\x0b\x32\x1d.host.authority.v1.WorkSealV1R\x04seal\x12[\n\x11operation_binding\x18\x1b \x01(\x0b\x32).host.authority.v1.WorkOperationBindingV1H\x07R\x10operationBinding\x88\x01\x01\x42\x14\n\x12_parent_session_idB\x0f\n\r_workspace_idB\r\n\x0b_project_idB\x17\n\x15_owner_principal_kindB\x11\n\x0f_owner_agent_idB\x12\n\x10_organization_idB\x0c\n\n_grant_hopB\x14\n\x12_operation_binding\"\xc0\x01\n\nWorkSealV1\x12\'\n\x0fprincipal_epoch\x18\x01 \x01(\x04R\x0eprincipalEpoch\x12\'\n\x0finstallation_id\x18\x02 \x01(\tR\x0einstallationId\x12\x33\n\x15installation_revision\x18\x03 \x01(\x04R\x14installationRevisionJ\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06R\x11\x62uild_incarnationR\x0cimage_digest\"u\n\x16WorkOperationBindingV1\x12\x1d\n\nbinding_id\x18\x01 \x01(\tR\tbindingId\x12\x1a\n\x08revision\x18\x02 \x01(\x04R\x08revision\x12 \n\x0bincarnation\x18\x03 \x01(\x04R\x0bincarnation\"o\n\x0bWorkScopeV1\x12#\n\rresource_kind\x18\x01 \x01(\tR\x0cresourceKind\x12\x18\n\x07\x61\x63tions\x18\x02 \x03(\tR\x07\x61\x63tions\x12!\n\x0cresource_ids\x18\x03 \x03(\tR\x0bresourceIds\"\x88\x03\n\x0bWorkActorV1\x12!\n\x0cprincipal_id\x18\x01 \x01(\tR\x0bprincipalId\x12%\n\x0eprincipal_kind\x18\x02 \x01(\tR\rprincipalKind\x12#\n\rdelegation_id\x18\x03 \x01(\tR\x0c\x64\x65legationId\x12\x45\n\x0egranted_scopes\x18\x04 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\rgrantedScopes\x12\x1e\n\x08\x61gent_id\x18\x05 \x01(\tH\x00R\x07\x61gentId\x88\x01\x01\x12,\n\x0forganization_id\x18\x06 \x01(\tH\x01R\x0eorganizationId\x88\x01\x01\x12\'\n\x0fprincipal_epoch\x18\x07 \x01(\x04R\x0eprincipalEpochB\x0b\n\t_agent_idB\x12\n\x10_organization_idJ\x04\x08\x08\x10\tJ\x04\x08\t\x10\nR\x0cimage_digestR\x11\x62uild_incarnation\"\xf2\x01\n\x0eWorkGrantHopV1\x12\x19\n\x08grant_id\x18\x01 \x01(\tR\x07grantId\x12?\n\tapprovers\x18\x02 \x03(\x0b\x32!.host.authority.v1.WorkApproverV1R\tapprovers\x12\x43\n\rgranted_scope\x18\x03 \x01(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0cgrantedScope\x12\x18\n\x07subject\x18\x04 \x01(\tR\x07subject\x12%\n\x0erequest_digest\x18\x05 \x01(\tR\rrequestDigest\"Z\n\x0eWorkApproverV1\x12!\n\x0cprincipal_id\x18\x01 \x01(\tR\x0bprincipalId\x12%\n\x0eprincipal_kind\x18\x02 \x01(\tR\rprincipalKind\"\xd9\x01\n\x12\x41pprovalRequiredV1\x12\x1d\n\nrequest_id\x18\x01 \x01(\tR\trequestId\x12G\n\x0frequested_scope\x18\x02 \x01(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0erequestedScope\x12\x18\n\x07subject\x18\x03 \x01(\tR\x07subject\x12%\n\x0erequest_digest\x18\x04 \x01(\tR\rrequestDigest\x12\x1a\n\x08\x61udience\x18\x05 \x01(\tR\x08\x61udienceb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$host/authority/v1/work_context.proto\x12\x11host.authority.v1\"\xaf\n\n\rWorkContextV1\x12\x10\n\x03typ\x18\x01 \x01(\tR\x03typ\x12\x1c\n\talgorithm\x18\x02 \x01(\tR\talgorithm\x12\x15\n\x06key_id\x18\x03 \x01(\tR\x05keyId\x12\x16\n\x06issuer\x18\x04 \x01(\tR\x06issuer\x12\x1a\n\x08\x61udience\x18\x05 \x01(\tR\x08\x61udience\x12&\n\x0fnot_before_unix\x18\x06 \x01(\x03R\rnotBeforeUnix\x12$\n\x0eissued_at_unix\x18\x07 \x01(\x03R\x0cissuedAtUnix\x12&\n\x0f\x65xpires_at_unix\x18\x08 \x01(\x03R\rexpiresAtUnix\x12\x14\n\x05nonce\x18\t \x01(\tR\x05nonce\x12\x35\n\x16\x61uthorization_revision\x18\n \x01(\x04R\x15\x61uthorizationRevision\x12#\n\rreplay_policy\x18\x0b \x01(\tR\x0creplayPolicy\x12\x1b\n\ttenant_id\x18\x0c \x01(\tR\x08tenantId\x12,\n\x12owner_principal_id\x18\r \x01(\tR\x10ownerPrincipalId\x12\x17\n\x07task_id\x18\x0e \x01(\tR\x06taskId\x12\x1d\n\nsession_id\x18\x0f \x01(\tR\tsessionId\x12/\n\x11parent_session_id\x18\x10 \x01(\tH\x00R\x0fparentSessionId\x88\x01\x01\x12I\n\x10\x61uthority_scopes\x18\x11 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0f\x61uthorityScopes\x12?\n\x0b\x61\x63tor_chain\x18\x12 \x03(\x0b\x32\x1e.host.authority.v1.WorkActorV1R\nactorChain\x12\x30\n\x14\x61ttribution_team_ids\x18\x13 \x03(\tR\x12\x61ttributionTeamIds\x12&\n\x0cworkspace_id\x18\x14 \x01(\tH\x01R\x0bworkspaceId\x88\x01\x01\x12\"\n\nproject_id\x18\x15 \x01(\tH\x02R\tprojectId\x88\x01\x01\x12\x35\n\x14owner_principal_kind\x18\x16 \x01(\tH\x03R\x12ownerPrincipalKind\x88\x01\x01\x12)\n\x0eowner_agent_id\x18\x17 \x01(\tH\x04R\x0cownerAgentId\x88\x01\x01\x12,\n\x0forganization_id\x18\x19 \x01(\tH\x05R\x0eorganizationId\x88\x01\x01\x12\x43\n\tgrant_hop\x18\x18 \x01(\x0b\x32!.host.authority.v1.WorkGrantHopV1H\x06R\x08grantHop\x88\x01\x01\x12\x31\n\x04seal\x18\x1a \x01(\x0b\x32\x1d.host.authority.v1.WorkSealV1R\x04seal\x12[\n\x11operation_binding\x18\x1b \x01(\x0b\x32).host.authority.v1.WorkOperationBindingV1H\x07R\x10operationBinding\x88\x01\x01\x42\x14\n\x12_parent_session_idB\x0f\n\r_workspace_idB\r\n\x0b_project_idB\x17\n\x15_owner_principal_kindB\x11\n\x0f_owner_agent_idB\x12\n\x10_organization_idB\x0c\n\n_grant_hopB\x14\n\x12_operation_binding\"\xc0\x01\n\nWorkSealV1\x12\'\n\x0fprincipal_epoch\x18\x01 \x01(\x04R\x0eprincipalEpoch\x12\'\n\x0finstallation_id\x18\x02 \x01(\tR\x0einstallationId\x12\x33\n\x15installation_revision\x18\x03 \x01(\x04R\x14installationRevisionJ\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06R\x11\x62uild_incarnationR\x0cimage_digest\"u\n\x16WorkOperationBindingV1\x12\x1d\n\nbinding_id\x18\x01 \x01(\tR\tbindingId\x12\x1a\n\x08revision\x18\x02 \x01(\x04R\x08revision\x12 \n\x0bincarnation\x18\x03 \x01(\x04R\x0bincarnation\"o\n\x0bWorkScopeV1\x12#\n\rresource_kind\x18\x01 \x01(\tR\x0cresourceKind\x12\x18\n\x07\x61\x63tions\x18\x02 \x03(\tR\x07\x61\x63tions\x12!\n\x0cresource_ids\x18\x03 \x03(\tR\x0bresourceIds\"\x88\x03\n\x0bWorkActorV1\x12!\n\x0cprincipal_id\x18\x01 \x01(\tR\x0bprincipalId\x12%\n\x0eprincipal_kind\x18\x02 \x01(\tR\rprincipalKind\x12#\n\rdelegation_id\x18\x03 \x01(\tR\x0c\x64\x65legationId\x12\x45\n\x0egranted_scopes\x18\x04 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\rgrantedScopes\x12\x1e\n\x08\x61gent_id\x18\x05 \x01(\tH\x00R\x07\x61gentId\x88\x01\x01\x12,\n\x0forganization_id\x18\x06 \x01(\tH\x01R\x0eorganizationId\x88\x01\x01\x12\'\n\x0fprincipal_epoch\x18\x07 \x01(\x04R\x0eprincipalEpochB\x0b\n\t_agent_idB\x12\n\x10_organization_idJ\x04\x08\x08\x10\tJ\x04\x08\t\x10\nR\x0cimage_digestR\x11\x62uild_incarnation\"\xf2\x01\n\x0eWorkGrantHopV1\x12\x19\n\x08grant_id\x18\x01 \x01(\tR\x07grantId\x12?\n\tapprovers\x18\x02 \x03(\x0b\x32!.host.authority.v1.WorkApproverV1R\tapprovers\x12\x43\n\rgranted_scope\x18\x03 \x01(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0cgrantedScope\x12\x18\n\x07subject\x18\x04 \x01(\tR\x07subject\x12%\n\x0erequest_digest\x18\x05 \x01(\tR\rrequestDigest\"Z\n\x0eWorkApproverV1\x12!\n\x0cprincipal_id\x18\x01 \x01(\tR\x0bprincipalId\x12%\n\x0eprincipal_kind\x18\x02 \x01(\tR\rprincipalKind\"\xd9\x01\n\x12\x41pprovalRequiredV1\x12\x1d\n\nrequest_id\x18\x01 \x01(\tR\trequestId\x12G\n\x0frequested_scope\x18\x02 \x01(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0erequestedScope\x12\x18\n\x07subject\x18\x03 \x01(\tR\x07subject\x12%\n\x0erequest_digest\x18\x04 \x01(\tR\rrequestDigest\x12\x1a\n\x08\x61udience\x18\x05 \x01(\tR\x08\x61udienceB/Z-gateway/pkg/gen/host/authority/v1;authorityv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'host.authority.v1.work_context_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z-gateway/pkg/gen/host/authority/v1;authorityv1' _globals['_WORKCONTEXTV1']._serialized_start=60 _globals['_WORKCONTEXTV1']._serialized_end=1387 _globals['_WORKSEALV1']._serialized_start=1390 diff --git a/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2.py b/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2.py index d8b7318d..fca4ced2 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2.py @@ -25,13 +25,14 @@ from authority_client._gen.host.authority.v1 import work_context_pb2 as host_dot_authority_dot_v1_dot_work__context__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%host/composition/v1/composition.proto\x12\x13host.composition.v1\x1a$host/authority/v1/work_context.proto\"\xff\x01\n\x14\x41pplyManifestRequest\x12\x41\n\x08manifest\x18\x01 \x01(\x0b\x32%.host.composition.v1.ModuleManifestV1R\x08manifest\x12?\n\x07\x63\x61rrier\x18\x02 \x01(\x0b\x32%.host.composition.v1.SignedManifestV1R\x07\x63\x61rrier\x12\x1e\n\ncredential\x18\x03 \x01(\tR\ncredential\x12\x43\n\tauthority\x18\x04 \x01(\x0b\x32%.host.composition.v1.SignedManifestV1R\tauthority\"\xb8\x02\n\x13\x41uthorityManifestV1\x12\x16\n\x06module\x18\x01 \x01(\tR\x06module\x12\x1e\n\ngeneration\x18\x02 \x01(\x04R\ngeneration\x12\x30\n\x14\x63ore_manifest_digest\x18\x03 \x01(\tR\x12\x63oreManifestDigest\x12=\n\x07methods\x18\x04 \x03(\x0b\x32#.host.composition.v1.MethodPolicyV1R\x07methods\x12\x45\n\x0escope_ceilings\x18\x05 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\rscopeCeilings\x12\x31\n\x05roles\x18\x06 \x03(\x0b\x32\x1b.host.composition.v1.RoleV1R\x05roles\"\x92\x01\n\x0eMethodPolicyV1\x12\x16\n\x06method\x18\x01 \x01(\tR\x06method\x12:\n\x08requires\x18\x02 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x08requires\x12,\n\x12\x61ny_checked_caller\x18\x03 \x01(\x08R\x10\x61nyCheckedCaller\"J\n\x10SignedManifestV1\x12\x1a\n\x08\x64ocument\x18\x01 \x01(\x0cR\x08\x64ocument\x12\x1a\n\x08\x65nvelope\x18\x02 \x01(\x0cR\x08\x65nvelope\"\x80\x01\n\x15\x41pplyManifestResponse\x12\x1c\n\tprincipal\x18\x01 \x01(\tR\tprincipal\x12\x1e\n\ngeneration\x18\x02 \x01(\x04R\ngeneration\x12)\n\x10installation_ids\x18\x03 \x03(\tR\x0finstallationIds\"\xe8\x02\n\x10ModuleManifestV1\x12\x16\n\x06module\x18\x01 \x01(\tR\x06module\x12\x1c\n\tprincipal\x18\x02 \x01(\tR\tprincipal\x12\x12\n\x04kind\x18\x03 \x01(\tR\x04kind\x12\x1e\n\ngeneration\x18\x04 \x01(\x04R\ngeneration\x12:\n\x08\x62indings\x18\x05 \x03(\x0b\x32\x1e.host.composition.v1.BindingV1R\x08\x62indings\x12J\n\x0eresource_kinds\x18\x06 \x03(\x0b\x32#.host.composition.v1.ResourceKindV1R\rresourceKinds\x12/\n\x04page\x18\x07 \x01(\x0b\x32\x1b.host.composition.v1.PageV1R\x04page\x12\x31\n\x05roles\x18\x08 \x03(\x0b\x32\x1b.host.composition.v1.RoleV1R\x05roles\"T\n\x06RoleV1\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12\x36\n\x06scopes\x18\x02 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\"\x8a\x02\n\tBindingV1\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x1a\n\x08\x61udience\x18\x02 \x01(\tR\x08\x61udience\x12\x43\n\rinvoke_scopes\x18\x03 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0cinvokeScopes\x12G\n\x0fheadless_scopes\x18\x04 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0eheadlessScopes\x12\x43\n\rlookup_scopes\x18\x05 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0clookupScopes\">\n\x0eResourceKindV1\x12\x12\n\x04kind\x18\x01 \x01(\tR\x04kind\x12\x18\n\x07\x61\x63tions\x18\x02 \x03(\tR\x07\x61\x63tions\"4\n\x06PageV1\x12\x14\n\x05title\x18\x01 \x01(\tR\x05title\x12\x14\n\x05order\x18\x02 \x01(\x05R\x05order2|\n\x12\x43ompositionService\x12\x66\n\rApplyManifest\x12).host.composition.v1.ApplyManifestRequest\x1a*.host.composition.v1.ApplyManifestResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%host/composition/v1/composition.proto\x12\x13host.composition.v1\x1a$host/authority/v1/work_context.proto\"\xff\x01\n\x14\x41pplyManifestRequest\x12\x41\n\x08manifest\x18\x01 \x01(\x0b\x32%.host.composition.v1.ModuleManifestV1R\x08manifest\x12?\n\x07\x63\x61rrier\x18\x02 \x01(\x0b\x32%.host.composition.v1.SignedManifestV1R\x07\x63\x61rrier\x12\x1e\n\ncredential\x18\x03 \x01(\tR\ncredential\x12\x43\n\tauthority\x18\x04 \x01(\x0b\x32%.host.composition.v1.SignedManifestV1R\tauthority\"\xb8\x02\n\x13\x41uthorityManifestV1\x12\x16\n\x06module\x18\x01 \x01(\tR\x06module\x12\x1e\n\ngeneration\x18\x02 \x01(\x04R\ngeneration\x12\x30\n\x14\x63ore_manifest_digest\x18\x03 \x01(\tR\x12\x63oreManifestDigest\x12=\n\x07methods\x18\x04 \x03(\x0b\x32#.host.composition.v1.MethodPolicyV1R\x07methods\x12\x45\n\x0escope_ceilings\x18\x05 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\rscopeCeilings\x12\x31\n\x05roles\x18\x06 \x03(\x0b\x32\x1b.host.composition.v1.RoleV1R\x05roles\"\x92\x01\n\x0eMethodPolicyV1\x12\x16\n\x06method\x18\x01 \x01(\tR\x06method\x12:\n\x08requires\x18\x02 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x08requires\x12,\n\x12\x61ny_checked_caller\x18\x03 \x01(\x08R\x10\x61nyCheckedCaller\"J\n\x10SignedManifestV1\x12\x1a\n\x08\x64ocument\x18\x01 \x01(\x0cR\x08\x64ocument\x12\x1a\n\x08\x65nvelope\x18\x02 \x01(\x0cR\x08\x65nvelope\"\x80\x01\n\x15\x41pplyManifestResponse\x12\x1c\n\tprincipal\x18\x01 \x01(\tR\tprincipal\x12\x1e\n\ngeneration\x18\x02 \x01(\x04R\ngeneration\x12)\n\x10installation_ids\x18\x03 \x03(\tR\x0finstallationIds\"\xe8\x02\n\x10ModuleManifestV1\x12\x16\n\x06module\x18\x01 \x01(\tR\x06module\x12\x1c\n\tprincipal\x18\x02 \x01(\tR\tprincipal\x12\x12\n\x04kind\x18\x03 \x01(\tR\x04kind\x12\x1e\n\ngeneration\x18\x04 \x01(\x04R\ngeneration\x12:\n\x08\x62indings\x18\x05 \x03(\x0b\x32\x1e.host.composition.v1.BindingV1R\x08\x62indings\x12J\n\x0eresource_kinds\x18\x06 \x03(\x0b\x32#.host.composition.v1.ResourceKindV1R\rresourceKinds\x12/\n\x04page\x18\x07 \x01(\x0b\x32\x1b.host.composition.v1.PageV1R\x04page\x12\x31\n\x05roles\x18\x08 \x03(\x0b\x32\x1b.host.composition.v1.RoleV1R\x05roles\"T\n\x06RoleV1\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12\x36\n\x06scopes\x18\x02 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x06scopes\"\x8a\x02\n\tBindingV1\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\x1a\n\x08\x61udience\x18\x02 \x01(\tR\x08\x61udience\x12\x43\n\rinvoke_scopes\x18\x03 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0cinvokeScopes\x12G\n\x0fheadless_scopes\x18\x04 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0eheadlessScopes\x12\x43\n\rlookup_scopes\x18\x05 \x03(\x0b\x32\x1e.host.authority.v1.WorkScopeV1R\x0clookupScopes\">\n\x0eResourceKindV1\x12\x12\n\x04kind\x18\x01 \x01(\tR\x04kind\x12\x18\n\x07\x61\x63tions\x18\x02 \x03(\tR\x07\x61\x63tions\"4\n\x06PageV1\x12\x14\n\x05title\x18\x01 \x01(\tR\x05title\x12\x14\n\x05order\x18\x02 \x01(\x05R\x05order2|\n\x12\x43ompositionService\x12\x66\n\rApplyManifest\x12).host.composition.v1.ApplyManifestRequest\x1a*.host.composition.v1.ApplyManifestResponseB3Z1gateway/pkg/gen/host/composition/v1;compositionv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'host.composition.v1.composition_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z1gateway/pkg/gen/host/composition/v1;compositionv1' _globals['_APPLYMANIFESTREQUEST']._serialized_start=101 _globals['_APPLYMANIFESTREQUEST']._serialized_end=356 _globals['_AUTHORITYMANIFESTV1']._serialized_start=359 diff --git a/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2_grpc.py b/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2_grpc.py index 13aa4858..cb63d90e 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2_grpc.py +++ b/libraries/authority-client/python/authority_client/_gen/host/composition/v1/composition_pb2_grpc.py @@ -26,7 +26,7 @@ class CompositionServiceStub(object): - """CompositionService is implemented by the host and by the authority gateway. + """CompositionService is implemented by the host and by the local authority. """ def __init__(self, channel): @@ -43,7 +43,7 @@ def __init__(self, channel): class CompositionServiceServicer(object): - """CompositionService is implemented by the host and by the authority gateway. + """CompositionService is implemented by the host and by the local authority. """ def ApplyManifest(self, request, context): @@ -70,7 +70,7 @@ def add_CompositionServiceServicer_to_server(servicer, server): # This class is part of an EXPERIMENTAL API. class CompositionService(object): - """CompositionService is implemented by the host and by the authority gateway. + """CompositionService is implemented by the host and by the local authority. """ @staticmethod diff --git a/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2.py b/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2.py index c204a172..22efabff 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2.py @@ -24,13 +24,14 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\'host/installation/v1/installation.proto\x12\x14host.installation.v1\"\x8d\x01\n\x0eInstallRequest\x12\'\n\x0forganization_id\x18\x01 \x01(\tR\x0eorganizationId\x12\x16\n\x06target\x18\x02 \x01(\tR\x06target\x12\x12\n\x04role\x18\x03 \x01(\tR\x04role\x12&\n\x0fowner_person_id\x18\x04 \x01(\tR\rownerPersonId\"\x7f\n\x12GrantToTeamRequest\x12\'\n\x0finstallation_id\x18\x01 \x01(\tR\x0einstallationId\x12\x17\n\x07team_id\x18\x02 \x01(\tR\x06teamId\x12\'\n\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\"6\n\x0bListRequest\x12\'\n\x0forganization_id\x18\x01 \x01(\tR\x0eorganizationId\"X\n\x0cListResponse\x12H\n\rinstallations\x18\x01 \x03(\x0b\x32\".host.installation.v1.InstallationR\rinstallations\"\x96\x03\n\x0cInstallation\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\'\n\x0forganization_id\x18\x02 \x01(\tR\x0eorganizationId\x12\x16\n\x06target\x18\x03 \x01(\tR\x06target\x12\x41\n\x06status\x18\x04 \x01(\x0e\x32).host.installation.v1.Installation.StatusR\x06status\x12\x1a\n\x08revision\x18\x05 \x01(\x04R\x08revision\x12\x12\n\x04role\x18\x06 \x01(\tR\x04role\x12\x19\n\x08team_ids\x18\x07 \x03(\tR\x07teamIds\x12,\n\x12\x61gent_principal_id\x18\x08 \x01(\tR\x10\x61gentPrincipalId\x12\x1c\n\tnamespace\x18\t \x01(\tR\tnamespace\"[\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x12\n\x0eSTATUS_PENDING\x10\x01\x12\x11\n\rSTATUS_ACTIVE\x10\x02\x12\x12\n\x0eSTATUS_REVOKED\x10\x03\"\\\n\x12InstallationNotice\x12\x46\n\x0cinstallation\x18\x01 \x01(\x0b\x32\".host.installation.v1.InstallationR\x0cinstallation\"\x11\n\x0fInstallationAck2\x96\x02\n\x13InstallationService\x12S\n\x07Install\x12$.host.installation.v1.InstallRequest\x1a\".host.installation.v1.Installation\x12[\n\x0bGrantToTeam\x12(.host.installation.v1.GrantToTeamRequest\x1a\".host.installation.v1.Installation\x12M\n\x04List\x12!.host.installation.v1.ListRequest\x1a\".host.installation.v1.ListResponse2p\n\x12InstallableService\x12Z\n\x07Install\x12(.host.installation.v1.InstallationNotice\x1a%.host.installation.v1.InstallationAckb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\'host/installation/v1/installation.proto\x12\x14host.installation.v1\"\x8d\x01\n\x0eInstallRequest\x12\'\n\x0forganization_id\x18\x01 \x01(\tR\x0eorganizationId\x12\x16\n\x06target\x18\x02 \x01(\tR\x06target\x12\x12\n\x04role\x18\x03 \x01(\tR\x04role\x12&\n\x0fowner_person_id\x18\x04 \x01(\tR\rownerPersonId\"\x7f\n\x12GrantToTeamRequest\x12\'\n\x0finstallation_id\x18\x01 \x01(\tR\x0einstallationId\x12\x17\n\x07team_id\x18\x02 \x01(\tR\x06teamId\x12\'\n\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\"6\n\x0bListRequest\x12\'\n\x0forganization_id\x18\x01 \x01(\tR\x0eorganizationId\"X\n\x0cListResponse\x12H\n\rinstallations\x18\x01 \x03(\x0b\x32\".host.installation.v1.InstallationR\rinstallations\"\x96\x03\n\x0cInstallation\x12\x0e\n\x02id\x18\x01 \x01(\tR\x02id\x12\'\n\x0forganization_id\x18\x02 \x01(\tR\x0eorganizationId\x12\x16\n\x06target\x18\x03 \x01(\tR\x06target\x12\x41\n\x06status\x18\x04 \x01(\x0e\x32).host.installation.v1.Installation.StatusR\x06status\x12\x1a\n\x08revision\x18\x05 \x01(\x04R\x08revision\x12\x12\n\x04role\x18\x06 \x01(\tR\x04role\x12\x19\n\x08team_ids\x18\x07 \x03(\tR\x07teamIds\x12,\n\x12\x61gent_principal_id\x18\x08 \x01(\tR\x10\x61gentPrincipalId\x12\x1c\n\tnamespace\x18\t \x01(\tR\tnamespace\"[\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x12\n\x0eSTATUS_PENDING\x10\x01\x12\x11\n\rSTATUS_ACTIVE\x10\x02\x12\x12\n\x0eSTATUS_REVOKED\x10\x03\"\\\n\x12InstallationNotice\x12\x46\n\x0cinstallation\x18\x01 \x01(\x0b\x32\".host.installation.v1.InstallationR\x0cinstallation\"\x11\n\x0fInstallationAck2\x96\x02\n\x13InstallationService\x12S\n\x07Install\x12$.host.installation.v1.InstallRequest\x1a\".host.installation.v1.Installation\x12[\n\x0bGrantToTeam\x12(.host.installation.v1.GrantToTeamRequest\x1a\".host.installation.v1.Installation\x12M\n\x04List\x12!.host.installation.v1.ListRequest\x1a\".host.installation.v1.ListResponse2p\n\x12InstallableService\x12Z\n\x07Install\x12(.host.installation.v1.InstallationNotice\x1a%.host.installation.v1.InstallationAckB5Z3gateway/pkg/gen/host/installation/v1;installationv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'host.installation.v1.installation_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z3gateway/pkg/gen/host/installation/v1;installationv1' _globals['_INSTALLREQUEST']._serialized_start=66 _globals['_INSTALLREQUEST']._serialized_end=207 _globals['_GRANTTOTEAMREQUEST']._serialized_start=209 diff --git a/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2_grpc.py b/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2_grpc.py index a869c6b9..a00c92f6 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2_grpc.py +++ b/libraries/authority-client/python/authority_client/_gen/host/installation/v1/installation_pb2_grpc.py @@ -26,7 +26,7 @@ class InstallationServiceStub(object): - """InstallationService is implemented by the host and by the authority gateway. + """InstallationService is implemented by the host and by the local authority. """ def __init__(self, channel): @@ -53,7 +53,7 @@ def __init__(self, channel): class InstallationServiceServicer(object): - """InstallationService is implemented by the host and by the authority gateway. + """InstallationService is implemented by the host and by the local authority. """ def Install(self, request, context): @@ -107,7 +107,7 @@ def add_InstallationServiceServicer_to_server(servicer, server): # This class is part of an EXPERIMENTAL API. class InstallationService(object): - """InstallationService is implemented by the host and by the authority gateway. + """InstallationService is implemented by the host and by the local authority. """ @staticmethod diff --git a/libraries/authority-client/python/authority_client/_gen/host/session/v1/session_pb2.py b/libraries/authority-client/python/authority_client/_gen/host/session/v1/session_pb2.py index fd34039d..41fdcff7 100644 --- a/libraries/authority-client/python/authority_client/_gen/host/session/v1/session_pb2.py +++ b/libraries/authority-client/python/authority_client/_gen/host/session/v1/session_pb2.py @@ -24,13 +24,14 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dhost/session/v1/session.proto\x12\x0fhost.session.v1\"\x1a\n\x18ListFixturePeopleRequest\"S\n\x19ListFixturePeopleResponse\x12\x36\n\x06people\x18\x01 \x03(\x0b\x32\x1e.host.session.v1.FixturePersonR\x06people\"\xc1\x01\n\rFixturePerson\x12\x1b\n\tperson_id\x18\x01 \x01(\tR\x08personId\x12\x14\n\x05\x65mail\x18\x02 \x01(\tR\x05\x65mail\x12\'\n\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\x12\x14\n\x05roles\x18\x04 \x03(\tR\x05roles\x12\x19\n\x08team_ids\x18\x05 \x03(\tR\x07teamIds\x12#\n\rfixture_token\x18\x06 \x01(\tR\x0c\x66ixtureToken\"\x10\n\x0e\x43urrentRequest\"4\n\rSignInRequest\x12#\n\rfixture_token\x18\x01 \x01(\tR\x0c\x66ixtureToken\"\xb7\x01\n\x07Session\x12\x1d\n\nsession_id\x18\x01 \x01(\tR\tsessionId\x12\x1b\n\tperson_id\x18\x02 \x01(\tR\x08personId\x12\'\n\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\x12\x14\n\x05roles\x18\x04 \x03(\tR\x05roles\x12\x19\n\x08team_ids\x18\x05 \x03(\tR\x07teamIds\x12\x16\n\x06\x62\x65\x61rer\x18\x06 \x01(\tR\x06\x62\x65\x61rer2\x86\x02\n\x0eSessionService\x12\x42\n\x06SignIn\x12\x1e.host.session.v1.SignInRequest\x1a\x18.host.session.v1.Session\x12\x44\n\x07\x43urrent\x12\x1f.host.session.v1.CurrentRequest\x1a\x18.host.session.v1.Session\x12j\n\x11ListFixturePeople\x12).host.session.v1.ListFixturePeopleRequest\x1a*.host.session.v1.ListFixturePeopleResponseb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dhost/session/v1/session.proto\x12\x0fhost.session.v1\"\x1a\n\x18ListFixturePeopleRequest\"S\n\x19ListFixturePeopleResponse\x12\x36\n\x06people\x18\x01 \x03(\x0b\x32\x1e.host.session.v1.FixturePersonR\x06people\"\xc1\x01\n\rFixturePerson\x12\x1b\n\tperson_id\x18\x01 \x01(\tR\x08personId\x12\x14\n\x05\x65mail\x18\x02 \x01(\tR\x05\x65mail\x12\'\n\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\x12\x14\n\x05roles\x18\x04 \x03(\tR\x05roles\x12\x19\n\x08team_ids\x18\x05 \x03(\tR\x07teamIds\x12#\n\rfixture_token\x18\x06 \x01(\tR\x0c\x66ixtureToken\"\x10\n\x0e\x43urrentRequest\"4\n\rSignInRequest\x12#\n\rfixture_token\x18\x01 \x01(\tR\x0c\x66ixtureToken\"\xa3\x02\n\x07Session\x12\x1d\n\nsession_id\x18\x01 \x01(\tR\tsessionId\x12\x1b\n\tperson_id\x18\x02 \x01(\tR\x08personId\x12\'\n\x0forganization_id\x18\x03 \x01(\tR\x0eorganizationId\x12\x14\n\x05roles\x18\x04 \x03(\tR\x05roles\x12\x19\n\x08team_ids\x18\x05 \x03(\tR\x07teamIds\x12\x16\n\x06\x62\x65\x61rer\x18\x06 \x01(\tR\x06\x62\x65\x61rer\x12.\n\x13person_display_name\x18\x07 \x01(\tR\x11personDisplayName\x12:\n\x19organization_display_name\x18\x08 \x01(\tR\x17organizationDisplayName2\x86\x02\n\x0eSessionService\x12\x42\n\x06SignIn\x12\x1e.host.session.v1.SignInRequest\x1a\x18.host.session.v1.Session\x12\x44\n\x07\x43urrent\x12\x1f.host.session.v1.CurrentRequest\x1a\x18.host.session.v1.Session\x12j\n\x11ListFixturePeople\x12).host.session.v1.ListFixturePeopleRequest\x1a*.host.session.v1.ListFixturePeopleResponseB+Z)gateway/pkg/gen/host/session/v1;sessionv1b\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'host.session.v1.session_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - DESCRIPTOR._loaded_options = None + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'Z)gateway/pkg/gen/host/session/v1;sessionv1' _globals['_LISTFIXTUREPEOPLEREQUEST']._serialized_start=50 _globals['_LISTFIXTUREPEOPLEREQUEST']._serialized_end=76 _globals['_LISTFIXTUREPEOPLERESPONSE']._serialized_start=78 @@ -42,7 +43,7 @@ _globals['_SIGNINREQUEST']._serialized_start=377 _globals['_SIGNINREQUEST']._serialized_end=429 _globals['_SESSION']._serialized_start=432 - _globals['_SESSION']._serialized_end=615 - _globals['_SESSIONSERVICE']._serialized_start=618 - _globals['_SESSIONSERVICE']._serialized_end=880 + _globals['_SESSION']._serialized_end=723 + _globals['_SESSIONSERVICE']._serialized_start=726 + _globals['_SESSIONSERVICE']._serialized_end=988 # @@protoc_insertion_point(module_scope) diff --git a/libraries/authority-client/python/authority_client/work_context.py b/libraries/authority-client/python/authority_client/work_context.py new file mode 100644 index 00000000..657fc98f --- /dev/null +++ b/libraries/authority-client/python/authority_client/work_context.py @@ -0,0 +1,101 @@ +"""Non-verifying projection of the Work Context already bound by a hop stamp. + +Pass the incoming headers and this run's delivered hop proof to ``read_claims``. +This is a reader, not Core's structural validator or a verifier: it checks neither +signature, liveness, revocation nor delegation. In warning mode the hop may have +forwarded a refused context; its advisory remains diagnostic, never a grant. +""" + +from __future__ import annotations + +import base64 +from dataclasses import dataclass +from collections.abc import Iterable, Mapping +from codefly_hop import read, NoStamp + +from google.protobuf.message import DecodeError + +from ._gen.host.authority.v1.work_context_pb2 import WorkContextV1 + +# The existing Core and Python SDK envelope bound, before decoding allocates. +MAX_TOKEN_BYTES = 32 * 1024 + + +class UnreadableContext(ValueError): + """The forwarded token cannot be projected through the published wire type.""" + + +@dataclass(frozen=True) +class Scope: + resource_kind: str + actions: tuple[str, ...] + resource_ids: tuple[str, ...] + + +@dataclass(frozen=True) +class Claims: + audience: str + # Core's effective scopes: the last actor's grants, or the owner's if no actor. + scopes: tuple[Scope, ...] + + def allows(self, kind: str, action: str, resource_id: str = "") -> bool: + """One exact action on one resource; empty ID asks for the whole kind. + + Each grant is considered independently. Actions are literal, as in Core's + scope containment and the Python SDK; no admin implication or wildcard + expansion happens here. A kind-wide grant includes any named resource. + """ + if not kind or not action: + return False + return any( + scope.resource_kind == kind + and action in scope.actions + and (not scope.resource_ids or bool(resource_id) and resource_id in scope.resource_ids) + for scope in self.scopes + ) + + +def read_claims(headers: Mapping[str, str] | Iterable[tuple[str, str]], proof: str) -> Claims: + """Read an already hop-bound context without another verification/replay call. + + Uses the published generated protobuf type. The canonical-envelope/payload + checks follow the existing Python SDK's algorithm, maintained here during + migration rather than imported from its private helpers. Unknown fields are + refused rather than silently losing a restriction. Consumers still check audience and resolve the + exact domain resource; this projection alone is never proof of authority. + """ + try: + token = read(headers, proof).context + except (NoStamp, TypeError, ValueError) as error: + raise UnreadableContext("context requires this run's hop proof and matching stamp") from error + if not token: + raise UnreadableContext("context requires a token bound by the hop stamp") + if not token.isascii() or len(token) > MAX_TOKEN_BYTES or token.count(".") != 1: + raise UnreadableContext("expected a bounded . context") + payload_segment, signature_segment = token.split(".") + payload = _decode_segment(payload_segment) + if len(_decode_segment(signature_segment)) != 64: + raise UnreadableContext("expected a 64-byte signature") + context = WorkContextV1() + try: + context.ParseFromString(payload) + except DecodeError as error: + raise UnreadableContext("payload is not a WorkContextV1") from error + context.DiscardUnknownFields() + if context.SerializeToString(deterministic=True) != payload or not context.audience: + raise UnreadableContext("payload is noncanonical, has unknown fields or names no audience") + scopes = context.actor_chain[-1].granted_scopes if context.actor_chain else context.authority_scopes + return Claims( + audience=context.audience, + scopes=tuple(Scope(s.resource_kind, tuple(s.actions), tuple(s.resource_ids)) for s in scopes), + ) + + +def _decode_segment(segment: str) -> bytes: + try: + decoded = base64.urlsafe_b64decode(segment + "=" * (-len(segment) % 4)) + except ValueError as error: + raise UnreadableContext("context segment is not base64url") from error + if base64.urlsafe_b64encode(decoded).rstrip(b"=").decode("ascii") != segment: + raise UnreadableContext("context segment is not canonical base64url") + return decoded diff --git a/libraries/authority-client/python/pyproject.toml b/libraries/authority-client/python/pyproject.toml index b719293a..77ddd497 100644 --- a/libraries/authority-client/python/pyproject.toml +++ b/libraries/authority-client/python/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "authority-client" version = "0.0.1" -dependencies = ["protobuf>=5.29.3,<7", "grpcio>=1.71.0", "googleapis-common-protos"] +dependencies = ["protobuf>=5.29.3,<7", "grpcio>=1.71.0", "googleapis-common-protos", "codefly-hop @ git+https://github.com/codefly-dev/authority@cac1f6b3dcb6c9bca8a6fa7ee3f8135b8f5175ae#subdirectory=libraries/hop/python"] [build-system] requires = ["setuptools>=68"] diff --git a/libraries/authority-client/python/tests/test_work_context.py b/libraries/authority-client/python/tests/test_work_context.py new file mode 100644 index 00000000..1189ad72 --- /dev/null +++ b/libraries/authority-client/python/tests/test_work_context.py @@ -0,0 +1,138 @@ +import base64 +import hashlib +import json +from dataclasses import FrozenInstanceError +from pathlib import Path + +import pytest + +from authority_client._gen.host.authority.v1.work_context_pb2 import WorkContextV1 +from authority_client.work_context import MAX_TOKEN_BYTES, Claims, Scope, UnreadableContext, read_claims as bound_claims +from codefly_hop import CONTEXT_KEY, WORK_CONTEXT_KEY, NoStamp, read + +FIXTURES = json.loads((Path(__file__).parents[2] / "testdata/claims.json").read_text()) +STAMP = json.loads((Path(__file__).parents[3] / "hop/testdata/stamped.json").read_text()) + + +def read_claims(token): + headers = dict(STAMP["headers"]) + headers[WORK_CONTEXT_KEY] = token + headers[CONTEXT_KEY] = hashlib.sha256(token.encode(errors="surrogatepass")).hexdigest() + return bound_claims(headers, STAMP["proof"]) + + +def encoded(payload): + return base64.urlsafe_b64encode(payload).rstrip(b"=").decode() + + +def token_for(context): + # Projection-only unit tests. These are not authenticated capabilities. + return encoded(context.SerializeToString(deterministic=True)) + "." + encoded(bytes(64)) + + +@pytest.mark.parametrize("fixture", FIXTURES, ids=lambda f: f["name"]) +def test_core_minted_and_verified_contexts_match_the_owner_projection(fixture): + claims = read_claims(fixture["token"]) + assert claims.audience == fixture["audience"] + assert claims.scopes == tuple( + Scope(s["resource_kind"], tuple(s.get("actions", [])), tuple(s.get("resource_ids", []))) + for s in fixture["scopes"] + ) + for probe in fixture["probes"]: + assert claims.allows(probe["kind"], probe["action"], probe["resource_id"]) == probe["allowed"] + + +def test_resource_ids_and_actions_are_never_combined_across_grants(): + context = WorkContextV1(audience="model") + context.authority_scopes.add(resource_kind="profiles", actions=["read"], resource_ids=["a"]) + context.authority_scopes.add(resource_kind="profiles", actions=["invoke"], resource_ids=["b"]) + claims = read_claims(token_for(context)) + assert claims.allows("profiles", "read", "a") + assert claims.allows("profiles", "invoke", "b") + assert not claims.allows("profiles", "invoke", "a") + assert not claims.allows("profiles", "read", "b") + assert not claims.allows("profiles", "read") + assert not claims.allows("other", "read", "a") + with pytest.raises(FrozenInstanceError): + claims.audience = "other" + + +def test_last_actor_grants_are_used_even_when_empty(): + context = WorkContextV1(audience="model") + context.authority_scopes.add(resource_kind="profiles", actions=["read", "invoke"]) + first = context.actor_chain.add(principal_id="first") + first.granted_scopes.add(resource_kind="profiles", actions=["read"], resource_ids=["a"]) + claims = read_claims(token_for(context)) + assert claims.allows("profiles", "read", "a") + assert not claims.allows("profiles", "invoke", "a") + assert not claims.allows("profiles", "read", "b") + context.actor_chain.add(principal_id="last") + assert read_claims(token_for(context)).scopes == () + + +def test_kind_wide_grants_include_resources_without_action_implications(): + claims = Claims("model", (Scope("profiles", ("read", "admin", "*"), ()),)) + assert claims.allows("profiles", "read") + assert claims.allows("profiles", "read", "a") + assert not claims.allows("profiles", "invoke", "a") + assert not claims.allows("profiles", "") + assert not claims.allows("", "read") + + +@pytest.mark.parametrize("token", ["", "abc", "a.b.c", ".", "a.b", "a." + encoded(bytes(64)), + "é.x", "\ud800.x", "a" * (MAX_TOKEN_BYTES + 1), encoded(b"{}") + "." + encoded(bytes(64)), + token_for(WorkContextV1()), token_for(WorkContextV1(audience="model")) + "=", +]) +def test_unreadable_envelopes_are_named(token): + with pytest.raises(UnreadableContext): + read_claims(token) + + +def test_unknown_nested_fields_and_duplicate_wire_fields_are_refused(): + context = WorkContextV1(audience="model") + scope = context.authority_scopes.add(resource_kind="profiles", actions=["read"]) + scope.ParseFromString(scope.SerializeToString() + b"\x78\x01") + with pytest.raises(UnreadableContext): + read_claims(token_for(context)) + payload = WorkContextV1(audience="model").SerializeToString() + with pytest.raises(UnreadableContext): + read_claims(encoded(payload + payload) + "." + encoded(bytes(64))) + + +def test_resource_projection_uses_the_bound_token_and_never_the_flat_stamp(): + fixture = next(f for f in FIXTURES if f["name"] == "delegated") + headers = dict(STAMP["headers"]) + headers[WORK_CONTEXT_KEY] = fixture["token"] + headers[CONTEXT_KEY] = hashlib.sha256(fixture["token"].encode()).hexdigest() + identity = read(headers, STAMP["proof"]) + claims = bound_claims(headers, STAMP["proof"]) + assert claims == read_claims(fixture["token"]) + assert not claims.allows("documents.collection", "read") # advisory is not a grant + other_token = next(f["token"] for f in FIXTURES if f["token"] != fixture["token"]) + for changed in [dict(headers, **{WORK_CONTEXT_KEY: other_token}), + list(headers.items()) + [(WORK_CONTEXT_KEY, fixture["token"])]]: + with pytest.raises(NoStamp): + read(changed, STAMP["proof"]) + headers.pop(CONTEXT_KEY) + with pytest.raises(UnreadableContext): + bound_claims(headers, STAMP["proof"]) + + +def test_projection_does_not_claim_to_verify_signature(): + token = FIXTURES[0]["token"] + assert read_claims(token) == read_claims(token.split(".")[0] + "." + encoded(bytes(64))) + + +@pytest.mark.parametrize("change", ["proof", "digest", "token", "duplicate", "missing"]) +def test_reader_itself_refuses_an_unbound_token(change): + headers = dict(STAMP["headers"]) + if change == "proof": headers["x-codefly-hop-proof"] = "forged" + if change == "digest": headers[CONTEXT_KEY] = "0" * 64 + if change == "token": headers[WORK_CONTEXT_KEY] = FIXTURES[0]["token"] + if change == "duplicate": headers = list(headers.items()) + [(WORK_CONTEXT_KEY,headers[WORK_CONTEXT_KEY])] + if change == "missing": headers.pop(CONTEXT_KEY) + with pytest.raises(UnreadableContext): bound_claims(headers,STAMP["proof"]) + + +def test_reader_refuses_an_empty_proof(): + with pytest.raises(UnreadableContext): bound_claims(STAMP["headers"], "") diff --git a/libraries/authority-client/testdata/claims.json b/libraries/authority-client/testdata/claims.json new file mode 100644 index 00000000..5ddc748b --- /dev/null +++ b/libraries/authority-client/testdata/claims.json @@ -0,0 +1,302 @@ +[ + { + "name": "delegated", + "token": "Chdjb2RlZmx5LndvcmstY29udGV4dC92MRIHRWQyNTUxORoNY29uZm9ybWFuY2UtMSIeaHR0cHM6Ly9hdXRob3JpdHkuY29kZWZseS50ZXN0Khhjb2RlZmx5LnRlc3QvY29uZm9ybWFuY2UwoMX11gY4oMX11gZAsOH11gZKJGZmNTI5NTQ0LTFjMzItNDM1MS1hOGEwLWI4ODA1MDQzMGYzNFAHWgppZGVtcG90ZW50YhJ0ZW5hbnQtY29uZm9ybWFuY2VqD3ByaW5jaXBhbC1vd25lcnIQdGFzay1jb25mb3JtYW5jZXokZDczMGEwNjYtYWFjYy00ZDE4LTk2ZGItODdhNTU1MmQ1NWZkggEkZjdkMjNmYWQtZTI1MS00M2MzLWFmMzItM2M1M2U5Y2MwZWMyigEOCgZyZWNvcmQSBHJlYWSSAXAKD3ByaW5jaXBhbC1hY3RvchIFYWdlbnQaFmRlbGVnYXRpb24tY29uZm9ybWFuY2UiIgoGcmVjb3JkEgRyZWFkGhJyZWNvcmQtY29uZm9ybWFuY2UqGGNvZGVmbHkudGVzdC9hY3RvcjoxLjAuMDgFsgEFaHVtYW7KARhvcmdhbml6YXRpb24tY29uZm9ybWFuY2XSAR4IAhIYaW5zdGFsbGF0aW9uLWNvbmZvcm1hbmNlGAM.xHzsawwSVUPXqyBR6EfEk5vB5GePrMJAhDnZfiuG24EIHCYevVpUAW-PXs_otAQ3vSWIhB-UoW9LOLa3pnpqBA", + "audience": "codefly.test/conformance", + "scopes": [ + { + "resource_kind": "record", + "actions": [ + "read" + ], + "resource_ids": [ + "record-conformance" + ] + } + ], + "probes": [ + { + "kind": "record", + "action": "read", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "read", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "read", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "read", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + } + ] + }, + { + "name": "delegated-operation", + "token": "Chdjb2RlZmx5LndvcmstY29udGV4dC92MRIHRWQyNTUxORoNY29uZm9ybWFuY2UtMSIeaHR0cHM6Ly9hdXRob3JpdHkuY29kZWZseS50ZXN0Khhjb2RlZmx5LnRlc3QvY29uZm9ybWFuY2UwoMX11gY4oMX11gZAsOH11gZKJGY0Y2M3MDc2LThlYTItNDI3Ny1iYjBlLTkwZDE0ZjYzZjAxZFAHWgppZGVtcG90ZW50YhJ0ZW5hbnQtY29uZm9ybWFuY2VqD3ByaW5jaXBhbC1vd25lcnIQdGFzay1jb25mb3JtYW5jZXokZmIwOTg1ZmMtMjcxNi00NWE0LTlhZDUtMTg1Y2UwZDA4MGIyggEkZjdkMjNmYWQtZTI1MS00M2MzLWFmMzItM2M1M2U5Y2MwZWMyigEOCgZyZWNvcmQSBHJlYWSSAXAKD3ByaW5jaXBhbC1hY3RvchIFYWdlbnQaFmRlbGVnYXRpb24tY29uZm9ybWFuY2UiIgoGcmVjb3JkEgRyZWFkGhJyZWNvcmQtY29uZm9ybWFuY2UqGGNvZGVmbHkudGVzdC9hY3RvcjoxLjAuMDgFsgEFaHVtYW7KARhvcmdhbml6YXRpb24tY29uZm9ybWFuY2XSAR4IAhIYaW5zdGFsbGF0aW9uLWNvbmZvcm1hbmNlGAPaAR8KGWJpbmRpbmctY29uZm9ybWFuY2UtYWN0b3IQBBgB.igwjaNWjv_k76P78HjVpZ0WGIVLTzC31Kjd8HGgb5l_If6jTF6H32sfynx00zewIoykxvRJuRLHXxFQk7ZUVDw", + "audience": "codefly.test/conformance", + "scopes": [ + { + "resource_kind": "record", + "actions": [ + "read" + ], + "resource_ids": [ + "record-conformance" + ] + } + ], + "probes": [ + { + "kind": "record", + "action": "read", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "read", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "read", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "read", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + } + ] + }, + { + "name": "grant", + "token": "Chdjb2RlZmx5LndvcmstY29udGV4dC92MRIHRWQyNTUxORoNY29uZm9ybWFuY2UtMSIeaHR0cHM6Ly9hdXRob3JpdHkuY29kZWZseS50ZXN0Khhjb2RlZmx5LnRlc3QvY29uZm9ybWFuY2UwoMX11gY4oMX11gZA3MX11gZKJGIzNzgwZDEwLWFlYzAtNGJlYS05YTdiLTk4NzU1ODAxYzc0MFAHWgpzaW5nbGUtdXNlYhJ0ZW5hbnQtY29uZm9ybWFuY2VqD3ByaW5jaXBhbC1vd25lcnIQdGFzay1jb25mb3JtYW5jZXokYWEwYzdmMTQtY2ViYy00MDY1LThmYTEtYmNlMzMyZjE0YmY1ggEkZDczMGEwNjYtYWFjYy00ZDE4LTk2ZGItODdhNTU1MmQ1NWZkigEOCgZyZWNvcmQSBHJlYWSSAXAKD3ByaW5jaXBhbC1hY3RvchIFYWdlbnQaFmRlbGVnYXRpb24tY29uZm9ybWFuY2UiIgoGcmVjb3JkEgRyZWFkGhJyZWNvcmQtY29uZm9ybWFuY2UqGGNvZGVmbHkudGVzdC9hY3RvcjoxLjAuMDgFkgFuCg9wcmluY2lwYWwtYWN0b3ISBWFnZW50GhFncmFudC1jb25mb3JtYW5jZSIlCgZyZWNvcmQSB2FwcHJvdmUaEnJlY29yZC1jb25mb3JtYW5jZSoYY29kZWZseS50ZXN0L2FjdG9yOjEuMC4wOAWyAQVodW1hbsIBgQEKEWdyYW50LWNvbmZvcm1hbmNlEhsKEnByaW5jaXBhbC1hcHByb3ZlchIFaHVtYW4aJQoGcmVjb3JkEgdhcHByb3ZlGhJyZWNvcmQtY29uZm9ybWFuY2UiFHJlc291cmNlLWNvbmZvcm1hbmNlKhJzaGEyNTY6Y29uZm9ybWFuY2XKARhvcmdhbml6YXRpb24tY29uZm9ybWFuY2XSAR4IAhIYaW5zdGFsbGF0aW9uLWNvbmZvcm1hbmNlGAM.8J0ouWQivBDUs32wk8jv_mHqE7DXmEbcoXjcgknZOgNKFh3Ap2UkTgswvMWkLfXrSsgEkCZlMxAtIoe20rwACA", + "audience": "codefly.test/conformance", + "scopes": [ + { + "resource_kind": "record", + "actions": [ + "approve" + ], + "resource_ids": [ + "record-conformance" + ] + } + ], + "probes": [ + { + "kind": "record", + "action": "approve", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "approve", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "approve", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "approve", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + } + ] + }, + { + "name": "operation", + "token": "Chdjb2RlZmx5LndvcmstY29udGV4dC92MRIHRWQyNTUxORoNY29uZm9ybWFuY2UtMSIeaHR0cHM6Ly9hdXRob3JpdHkuY29kZWZseS50ZXN0Khhjb2RlZmx5LnRlc3QvY29uZm9ybWFuY2UwoMX11gY4oMX11gZAsOH11gZKJGRiYzBmYzgyLWQ0YzQtNGQ1NC1iN2RmLThjZTRhODZkYjlhMlAHWgppZGVtcG90ZW50YhJ0ZW5hbnQtY29uZm9ybWFuY2VqD3ByaW5jaXBhbC1vd25lcnIQdGFzay1jb25mb3JtYW5jZXokNDYzY2FkNjgtOGQxYi00ZmJkLWFkOTctZmUzZjI5NjdkMGFhigEOCgZyZWNvcmQSBHJlYWSyAQVodW1hbsoBGG9yZ2FuaXphdGlvbi1jb25mb3JtYW5jZdIBHggCEhhpbnN0YWxsYXRpb24tY29uZm9ybWFuY2UYA9oBGQoTYmluZGluZy1jb25mb3JtYW5jZRAEGAE.HaWwuxTDaXO0JA1gjwrHJ764CGsfNCRpmn1PuMYByH70X2lm_nbrxSnlDXe80IYR7hoq4NFGjq-xon08KTZiBQ", + "audience": "codefly.test/conformance", + "scopes": [ + { + "resource_kind": "record", + "actions": [ + "read" + ] + } + ], + "probes": [ + { + "kind": "record", + "action": "read", + "resource_id": "", + "allowed": true + }, + { + "kind": "record", + "action": "read", + "resource_id": "other-resource", + "allowed": true + }, + { + "kind": "record", + "action": "read", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + } + ] + }, + { + "name": "session", + "token": "Chdjb2RlZmx5LndvcmstY29udGV4dC92MRIHRWQyNTUxORoNY29uZm9ybWFuY2UtMSIeaHR0cHM6Ly9hdXRob3JpdHkuY29kZWZseS50ZXN0Khhjb2RlZmx5LnRlc3QvY29uZm9ybWFuY2UwoMX11gY4oMX11gZAsOH11gZKJGEyMGFlZmY3LTg0MGMtNDY5My04Y2EzLTA0YTU0MDRiZDkxZVAHWgppZGVtcG90ZW50YhJ0ZW5hbnQtY29uZm9ybWFuY2VqD3ByaW5jaXBhbC1vd25lcnIQdGFzay1jb25mb3JtYW5jZXokZjdkMjNmYWQtZTI1MS00M2MzLWFmMzItM2M1M2U5Y2MwZWMyigEOCgZyZWNvcmQSBHJlYWSyAQVodW1hbsoBGG9yZ2FuaXphdGlvbi1jb25mb3JtYW5jZdIBHggCEhhpbnN0YWxsYXRpb24tY29uZm9ybWFuY2UYAw.QfE84kjvNVYJlmI60DaVgZZQQJebFu7uXjdzOkZh6MgVcpeZNM6bkdn9vCBNxWNtkdVp6N7wBrWHEuuHWradDQ", + "audience": "codefly.test/conformance", + "scopes": [ + { + "resource_kind": "record", + "actions": [ + "read" + ] + } + ], + "probes": [ + { + "kind": "record", + "action": "read", + "resource_id": "", + "allowed": true + }, + { + "kind": "record", + "action": "read", + "resource_id": "other-resource", + "allowed": true + }, + { + "kind": "record", + "action": "read", + "resource_id": "record-conformance", + "allowed": true + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "other-resource", + "allowed": false + }, + { + "kind": "record", + "action": "undeclared", + "resource_id": "record-conformance", + "allowed": false + } + ] + } +] diff --git a/libraries/authority-client/typescript/README.md b/libraries/authority-client/typescript/README.md new file mode 100644 index 00000000..a4ad57a3 --- /dev/null +++ b/libraries/authority-client/typescript/README.md @@ -0,0 +1,42 @@ +# Authority TypeScript client + +Codefly generates the RPC bindings exported by `@codefly-dev/authority-client`. +The handwritten, non-verifying claims reader has a separate public export: + +```ts +import { readClaims } from '@codefly-dev/authority-client/work-context'; + +const claims = readClaims(requestHeaders, proof); +// Compare claims.audience to the delivered module audience. +const allowed = claims.allows(resourceKind, action, exactResourceID); +``` + +The server-side Node reader takes header pairs (preserving repeats) or a header +map and the run-delivered proof. It requires exactly one proof, token and digest, +checks the proof and SHA-256 binding, then projects. Do not send the proof to a +browser. Readable claims alone are not proof of authentication. The +projection verifies neither signatures, current time, live revisions nor replay. +A warning-mode hop can bind a context the authority refused. Preserve the +integration's authentication and the module's audience, installed-definition, +ownership and live resource-visibility checks. + +`claims.scopes` contains frozen copies of the final actor's grants, or the owner's +when no actor exists. Empty final grants stay empty. Each scope is evaluated +independently. An omitted/empty resource ID asks for the whole kind; a restricted +grant cannot satisfy it. Whole-kind grants include named IDs. No wildcard or +admin implication, prefix/pattern match or cross-scope action/ID merging occurs. + +`UnreadableContext` names malformed/oversized envelopes, noncanonical base64url, +wrong signature length, unreadable protobuf, absent audience, unknown fields and +noncanonical protobuf bytes. This is a projection through the generated schema, +not Core's structural validator. Go also applies Core Decode's stronger schema +and attenuation checks. Shared Core-produced fixtures prove equal audience, +effective scope and exact-resource answers across the three language readers. + +Run `npm ci --ignore-scripts` and `npm test`. Tests import the built public package +exports, including the generated schema. No running SaaS, service or provider is +needed. Test signatures and fixed-clock fixtures are not live credentials. + +The generator owns `src/`, including its index. The helper lives at the package +root; preserved `package.json`/`tsconfig.json` scaffolds export and compile it +alongside generated bindings. Never edit the generated index to add this helper. diff --git a/libraries/authority-client/typescript/package-lock.json b/libraries/authority-client/typescript/package-lock.json new file mode 100644 index 00000000..a55157a0 --- /dev/null +++ b/libraries/authority-client/typescript/package-lock.json @@ -0,0 +1,66 @@ +{ + "name": "@codefly-dev/authority-client", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@codefly-dev/authority-client", + "version": "0.0.1", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "@connectrpc/connect": "^2.0.0" + }, + "devDependencies": { + "@types/node": "^26.6.5", + "typescript": "^5.9.3" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.16.0.tgz", + "integrity": "sha512-FWa0sPlqYGJgpTs6OxBRcL/AW4JT0OIO+W1ajerluoTVh8CV0B7XM1qsNCRgnkSCkRCgOICKHRQlY17jrsm0+Q==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@connectrpc/connect": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-2.2.0.tgz", + "integrity": "sha512-M63OQ1ZFcPUm85CuewJ9G9CMV8LjzGR9935xOnXNQGSazAbwMb3x2W7vXBYM1zqrP7XFD8uxp/dUAhirclgwnQ==", + "license": "Apache-2.0", + "peerDependencies": { + "@bufbuild/protobuf": "^2.7.0" + } + }, + "node_modules/@types/node": { + "version": "26.6.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz", + "integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.9.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/libraries/authority-client/typescript/package.json b/libraries/authority-client/typescript/package.json new file mode 100644 index 00000000..c5b6dfee --- /dev/null +++ b/libraries/authority-client/typescript/package.json @@ -0,0 +1,34 @@ +{ + "name": "@codefly-dev/authority-client", + "version": "0.0.1", + "type": "module", + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + }, + "./work-context": { + "types": "./dist/work-context.d.ts", + "import": "./dist/work-context.js" + } + }, + "files": [ + "dist", + "README.md" + ], + "scripts": { + "build": "tsc -p tsconfig.json", + "test": "npm run build && node --test tests/*.test.mjs" + }, + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "@connectrpc/connect": "^2.0.0" + }, + "devDependencies": { + "@types/node": "^26.6.5", + "typescript": "^5.9.3" + }, + "publishConfig": { + "registry": "https://npm.pkg.github.com" + } +} diff --git a/libraries/authority-client/typescript/src/gen/api_pb.ts b/libraries/authority-client/typescript/src/gen/api_pb.ts new file mode 100644 index 00000000..9abd2a3a --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/api_pb.ts @@ -0,0 +1,60 @@ +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file api.proto (package api, syntax proto3) +/* eslint-disable */ + +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2"; +import { file_google_api_annotations } from "./google/api/annotations_pb.js"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file api.proto. + */ +export const file_api: GenFile = /*@__PURE__*/ + fileDesc("CglhcGkucHJvdG8SA2FwaSIQCg5WZXJzaW9uUmVxdWVzdCIiCg9WZXJzaW9uUmVzcG9uc2USDwoHdmVyc2lvbhgBIAEoCTJYCg5HYXRld2F5U2VydmljZRJGCgdWZXJzaW9uEhMuYXBpLlZlcnNpb25SZXF1ZXN0GhQuYXBpLlZlcnNpb25SZXNwb25zZSIQgtPkkwIKEggvdmVyc2lvbkIVWhNnYXRld2F5L3BrZy9nZW47Z2VuYgZwcm90bzM", [file_google_api_annotations]); + +/** + * @generated from message api.VersionRequest + */ +export type VersionRequest = Message<"api.VersionRequest"> & { +}; + +/** + * Describes the message api.VersionRequest. + * Use `create(VersionRequestSchema)` to create a new message. + */ +export const VersionRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_api, 0); + +/** + * @generated from message api.VersionResponse + */ +export type VersionResponse = Message<"api.VersionResponse"> & { + /** + * @generated from field: string version = 1; + */ + version: string; +}; + +/** + * Describes the message api.VersionResponse. + * Use `create(VersionResponseSchema)` to create a new message. + */ +export const VersionResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_api, 1); + +/** + * @generated from service api.GatewayService + */ +export const GatewayService: GenService<{ + /** + * @generated from rpc api.GatewayService.Version + */ + version: { + methodKind: "unary"; + input: typeof VersionRequestSchema; + output: typeof VersionResponseSchema; + }, +}> = /*@__PURE__*/ + serviceDesc(file_api, 0); + diff --git a/libraries/authority-client/typescript/src/gen/buf/validate/validate_pb.ts b/libraries/authority-client/typescript/src/gen/buf/validate/validate_pb.ts new file mode 100644 index 00000000..3d68b110 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/buf/validate/validate_pb.ts @@ -0,0 +1,5034 @@ +// Copyright 2023-2026 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file buf/validate/validate.proto (package buf.validate, syntax proto2) +/* eslint-disable */ + +// [Protovalidate](https://protovalidate.com/) is the semantic validation library for Protobuf. +// It provides standard annotations to validate common rules on messages and fields, as well as the ability to use [CEL](https://cel.dev) to write custom rules. +// It's the next generation of [protoc-gen-validate](https://github.com/bufbuild/protoc-gen-validate). +// +// This package provides the options, messages, and enums that power Protovalidate. +// Apply its options to messages, fields, and oneofs in your Protobuf schemas to add validation rules: +// +// ```proto +// message User { +// string id = 1 [(buf.validate.field).string.uuid = true]; +// string first_name = 2 [(buf.validate.field).string.max_len = 64]; +// string last_name = 3 [(buf.validate.field).string.max_len = 64]; +// +// option (buf.validate.message).cel = { +// id: "first_name_requires_last_name" +// message: "last_name must be present if first_name is present" +// expression: "!has(this.first_name) || has(this.last_name)" +// }; +// } +// ``` +// +// These rules are enforced at runtime by language-specific libraries. +// See the [developer quickstart](https://protovalidate.com/quickstart/) to get started, or go directly to the runtime library for your language: +// [Go](https://github.com/bufbuild/protovalidate-go), +// [JavaScript/TypeScript](https://github.com/bufbuild/protovalidate-es), +// [Java](https://github.com/bufbuild/protovalidate-java), +// [Python](https://github.com/bufbuild/protovalidate-py), +// or [C++](https://github.com/bufbuild/protovalidate-cc). + +import type { GenEnum, GenExtension, GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2"; +import { enumDesc, extDesc, fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2"; +import type { Duration, FieldDescriptorProto_Type, FieldMask, FieldOptions, MessageOptions, OneofOptions, Timestamp } from "@bufbuild/protobuf/wkt"; +import { file_google_protobuf_descriptor, file_google_protobuf_duration, file_google_protobuf_field_mask, file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file buf/validate/validate.proto. + */ +export const file_buf_validate_validate: GenFile = /*@__PURE__*/ + fileDesc("ChtidWYvdmFsaWRhdGUvdmFsaWRhdGUucHJvdG8SDGJ1Zi52YWxpZGF0ZSI3CgRSdWxlEgoKAmlkGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSEgoKZXhwcmVzc2lvbhgDIAEoCSKGAQoMTWVzc2FnZVJ1bGVzEhYKDmNlbF9leHByZXNzaW9uGAUgAygJEh8KA2NlbBgDIAMoCzISLmJ1Zi52YWxpZGF0ZS5SdWxlEi0KBW9uZW9mGAQgAygLMh4uYnVmLnZhbGlkYXRlLk1lc3NhZ2VPbmVvZlJ1bGVKBAgBEAJSCGRpc2FibGVkIjQKEE1lc3NhZ2VPbmVvZlJ1bGUSDgoGZmllbGRzGAEgAygJEhAKCHJlcXVpcmVkGAIgASgIIh4KCk9uZW9mUnVsZXMSEAoIcmVxdWlyZWQYASABKAgiiwkKCkZpZWxkUnVsZXMSFgoOY2VsX2V4cHJlc3Npb24YHSADKAkSHwoDY2VsGBcgAygLMhIuYnVmLnZhbGlkYXRlLlJ1bGUSEAoIcmVxdWlyZWQYGSABKAgSJAoGaWdub3JlGBsgASgOMhQuYnVmLnZhbGlkYXRlLklnbm9yZRIpCgVmbG9hdBgBIAEoCzIYLmJ1Zi52YWxpZGF0ZS5GbG9hdFJ1bGVzSAASKwoGZG91YmxlGAIgASgLMhkuYnVmLnZhbGlkYXRlLkRvdWJsZVJ1bGVzSAASKQoFaW50MzIYAyABKAsyGC5idWYudmFsaWRhdGUuSW50MzJSdWxlc0gAEikKBWludDY0GAQgASgLMhguYnVmLnZhbGlkYXRlLkludDY0UnVsZXNIABIrCgZ1aW50MzIYBSABKAsyGS5idWYudmFsaWRhdGUuVUludDMyUnVsZXNIABIrCgZ1aW50NjQYBiABKAsyGS5idWYudmFsaWRhdGUuVUludDY0UnVsZXNIABIrCgZzaW50MzIYByABKAsyGS5idWYudmFsaWRhdGUuU0ludDMyUnVsZXNIABIrCgZzaW50NjQYCCABKAsyGS5idWYudmFsaWRhdGUuU0ludDY0UnVsZXNIABItCgdmaXhlZDMyGAkgASgLMhouYnVmLnZhbGlkYXRlLkZpeGVkMzJSdWxlc0gAEi0KB2ZpeGVkNjQYCiABKAsyGi5idWYudmFsaWRhdGUuRml4ZWQ2NFJ1bGVzSAASLwoIc2ZpeGVkMzIYCyABKAsyGy5idWYudmFsaWRhdGUuU0ZpeGVkMzJSdWxlc0gAEi8KCHNmaXhlZDY0GAwgASgLMhsuYnVmLnZhbGlkYXRlLlNGaXhlZDY0UnVsZXNIABInCgRib29sGA0gASgLMhcuYnVmLnZhbGlkYXRlLkJvb2xSdWxlc0gAEisKBnN0cmluZxgOIAEoCzIZLmJ1Zi52YWxpZGF0ZS5TdHJpbmdSdWxlc0gAEikKBWJ5dGVzGA8gASgLMhguYnVmLnZhbGlkYXRlLkJ5dGVzUnVsZXNIABInCgRlbnVtGBAgASgLMhcuYnVmLnZhbGlkYXRlLkVudW1SdWxlc0gAEi8KCHJlcGVhdGVkGBIgASgLMhsuYnVmLnZhbGlkYXRlLlJlcGVhdGVkUnVsZXNIABIlCgNtYXAYEyABKAsyFi5idWYudmFsaWRhdGUuTWFwUnVsZXNIABIlCgNhbnkYFCABKAsyFi5idWYudmFsaWRhdGUuQW55UnVsZXNIABIvCghkdXJhdGlvbhgVIAEoCzIbLmJ1Zi52YWxpZGF0ZS5EdXJhdGlvblJ1bGVzSAASMgoKZmllbGRfbWFzaxgcIAEoCzIcLmJ1Zi52YWxpZGF0ZS5GaWVsZE1hc2tSdWxlc0gAEjEKCXRpbWVzdGFtcBgWIAEoCzIcLmJ1Zi52YWxpZGF0ZS5UaW1lc3RhbXBSdWxlc0gAQgYKBHR5cGVKBAgYEBlKBAgaEBtSB3NraXBwZWRSDGlnbm9yZV9lbXB0eSJVCg9QcmVkZWZpbmVkUnVsZXMSHwoDY2VsGAEgAygLMhIuYnVmLnZhbGlkYXRlLlJ1bGVKBAgYEBlKBAgaEBtSB3NraXBwZWRSDGlnbm9yZV9lbXB0eSL4FgoKRmxvYXRSdWxlcxJ9CgVjb25zdBgBIAEoAkJuwkhrCmkKC2Zsb2F0LmNvbnN0Glp0aGlzICE9IGdldEZpZWxkKHJ1bGVzLCAnY29uc3QnKSA/ICdtdXN0IGVxdWFsICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnY29uc3QnKV0pIDogJycSmQEKAmx0GAIgASgCQooBwkiGAQqDAQoIZmxvYXQubHQadyFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiAodGhpcy5pc05hbigpIHx8IHRoaXMgPj0gcnVsZXMubHQpPyAnbXVzdCBiZSBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMubHRdKSA6ICcnSAASqQEKA2x0ZRgDIAEoAkKZAcJIlQEKkgEKCWZsb2F0Lmx0ZRqEASFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiAodGhpcy5pc05hbigpIHx8IHRoaXMgPiBydWxlcy5sdGUpPyAnbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMubHRlXSkgOiAnJ0gAEtAHCgJndBgEIAEoAkLBB8JIvQcKhgEKCGZsb2F0Lmd0GnohaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgKHRoaXMuaXNOYW4oKSB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwq9AQoLZmxvYXQuZ3RfbHQarQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ICYmICh0aGlzLmlzTmFuKCkgfHwgdGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwrHAQoVZmxvYXQuZ3RfbHRfZXhjbHVzaXZlGq0BaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmICh0aGlzLmlzTmFuKCkgfHwgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCkpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKzQEKDGZsb2F0Lmd0X2x0ZRq8AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndCAmJiAodGhpcy5pc05hbigpIHx8IHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnCtcBChZmbG9hdC5ndF9sdGVfZXhjbHVzaXZlGrwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3QgJiYgKHRoaXMuaXNOYW4oKSB8fCAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJydIARKcCAoDZ3RlGAUgASgCQowIwkiICAqVAQoJZmxvYXQuZ3RlGocBIWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmICh0aGlzLmlzTmFuKCkgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGVdKSA6ICcnCswBCgxmbG9hdC5ndGVfbHQauwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcy5pc05hbigpIHx8IHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCtYBChZmbG9hdC5ndGVfbHRfZXhjbHVzaXZlGrsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ZSAmJiAodGhpcy5pc05hbigpIHx8IChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrcAQoNZmxvYXQuZ3RlX2x0ZRrKAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMuaXNOYW4oKSB8fCB0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJycK5gEKF2Zsb2F0Lmd0ZV9sdGVfZXhjbHVzaXZlGsoBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3RlICYmICh0aGlzLmlzTmFuKCkgfHwgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSkpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJ0gBEnkKAmluGAYgAygCQm3CSGoKaAoIZmxvYXQuaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEnAKBm5vdF9pbhgHIAMoAkJgwkhdClsKDGZsb2F0Lm5vdF9pbhpLdGhpcyBpbiBydWxlcy5ub3RfaW4gPyAnbXVzdCBub3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtydWxlcy5ub3RfaW5dKSA6ICcnEm8KBmZpbml0ZRgIIAEoCEJfwkhcCloKDGZsb2F0LmZpbml0ZRpKcnVsZXMuZmluaXRlID8gKHRoaXMuaXNOYW4oKSB8fCB0aGlzLmlzSW5mKCkgPyAnbXVzdCBiZSBmaW5pdGUnIDogJycpIDogJycSKwoHZXhhbXBsZRgJIAMoAkIawkgXChUKDWZsb2F0LmV4YW1wbGUaBHRydWUqCQjoBxCAgICAAkILCglsZXNzX3RoYW5CDgoMZ3JlYXRlcl90aGFuIooXCgtEb3VibGVSdWxlcxJ+CgVjb25zdBgBIAEoAUJvwkhsCmoKDGRvdWJsZS5jb25zdBpadGhpcyAhPSBnZXRGaWVsZChydWxlcywgJ2NvbnN0JykgPyAnbXVzdCBlcXVhbCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2NvbnN0JyldKSA6ICcnEpoBCgJsdBgCIAEoAUKLAcJIhwEKhAEKCWRvdWJsZS5sdBp3IWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmICh0aGlzLmlzTmFuKCkgfHwgdGhpcyA+PSBydWxlcy5sdCk/ICdtdXN0IGJlIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5sdF0pIDogJydIABKqAQoDbHRlGAMgASgBQpoBwkiWAQqTAQoKZG91YmxlLmx0ZRqEASFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiAodGhpcy5pc05hbigpIHx8IHRoaXMgPiBydWxlcy5sdGUpPyAnbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMubHRlXSkgOiAnJ0gAEtUHCgJndBgEIAEoAULGB8JIwgcKhwEKCWRvdWJsZS5ndBp6IWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmICh0aGlzLmlzTmFuKCkgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndF0pIDogJycKvgEKDGRvdWJsZS5ndF9sdBqtAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3QgJiYgKHRoaXMuaXNOYW4oKSB8fCB0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCsgBChZkb3VibGUuZ3RfbHRfZXhjbHVzaXZlGq0BaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmICh0aGlzLmlzTmFuKCkgfHwgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCkpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKzgEKDWRvdWJsZS5ndF9sdGUavAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3QgJiYgKHRoaXMuaXNOYW4oKSB8fCB0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrYAQoXZG91YmxlLmd0X2x0ZV9leGNsdXNpdmUavAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndCAmJiAodGhpcy5pc05hbigpIHx8IChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJ0gBEqEICgNndGUYBSABKAFCkQjCSI0ICpYBCgpkb3VibGUuZ3RlGocBIWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmICh0aGlzLmlzTmFuKCkgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGVdKSA6ICcnCs0BCg1kb3VibGUuZ3RlX2x0GrsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndGUgJiYgKHRoaXMuaXNOYW4oKSB8fCB0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrXAQoXZG91YmxlLmd0ZV9sdF9leGNsdXNpdmUauwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3RlICYmICh0aGlzLmlzTmFuKCkgfHwgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSkpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCt0BCg5kb3VibGUuZ3RlX2x0ZRrKAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMuaXNOYW4oKSB8fCB0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJycK5wEKGGRvdWJsZS5ndGVfbHRlX2V4Y2x1c2l2ZRrKAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAodGhpcy5pc05hbigpIHx8IChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ6CgJpbhgGIAMoAUJuwkhrCmkKCWRvdWJsZS5pbhpcISh0aGlzIGluIGdldEZpZWxkKHJ1bGVzLCAnaW4nKSkgPyAnbXVzdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnaW4nKV0pIDogJycScQoGbm90X2luGAcgAygBQmHCSF4KXAoNZG91YmxlLm5vdF9pbhpLdGhpcyBpbiBydWxlcy5ub3RfaW4gPyAnbXVzdCBub3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtydWxlcy5ub3RfaW5dKSA6ICcnEnAKBmZpbml0ZRgIIAEoCEJgwkhdClsKDWRvdWJsZS5maW5pdGUaSnJ1bGVzLmZpbml0ZSA/ICh0aGlzLmlzTmFuKCkgfHwgdGhpcy5pc0luZigpID8gJ211c3QgYmUgZmluaXRlJyA6ICcnKSA6ICcnEiwKB2V4YW1wbGUYCSADKAFCG8JIGAoWCg5kb3VibGUuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4isBQKCkludDMyUnVsZXMSfQoFY29uc3QYASABKAVCbsJIawppCgtpbnQzMi5jb25zdBpadGhpcyAhPSBnZXRGaWVsZChydWxlcywgJ2NvbnN0JykgPyAnbXVzdCBlcXVhbCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2NvbnN0JyldKSA6ICcnEoQBCgJsdBgCIAEoBUJ2wkhzCnEKCGludDMyLmx0GmUhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+PSBydWxlcy5sdD8gJ211c3QgYmUgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmx0XSkgOiAnJ0gAEpUBCgNsdGUYAyABKAVChQHCSIEBCn8KCWludDMyLmx0ZRpyIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPiBydWxlcy5sdGU/ICdtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5sdGVdKSA6ICcnSAAS+QYKAmd0GAQgASgFQuoGwkjmBgp0CghpbnQzMi5ndBpoIWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmIHRoaXMgPD0gcnVsZXMuZ3Q/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndF0pIDogJycKrQEKC2ludDMyLmd0X2x0Gp0BaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndCAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwq1AQoVaW50MzIuZ3RfbHRfZXhjbHVzaXZlGpsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKvQEKDGludDMyLmd0X2x0ZRqsAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndCAmJiAodGhpcyA+IHJ1bGVzLmx0ZSB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJycKxQEKFmludDMyLmd0X2x0ZV9leGNsdXNpdmUaqgFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndCAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJ0gBEsUHCgNndGUYBSABKAVCtQfCSLEHCoIBCglpbnQzMi5ndGUadSFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDwgcnVsZXMuZ3RlPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlXSkgOiAnJwq8AQoMaW50MzIuZ3RlX2x0GqsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCsQBChZpbnQzMi5ndGVfbHRfZXhjbHVzaXZlGqkBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrMAQoNaW50MzIuZ3RlX2x0ZRq6AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJwrUAQoXaW50MzIuZ3RlX2x0ZV9leGNsdXNpdmUauAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdGVdKSA6ICcnSAESeQoCaW4YBiADKAVCbcJIagpoCghpbnQzMi5pbhpcISh0aGlzIGluIGdldEZpZWxkKHJ1bGVzLCAnaW4nKSkgPyAnbXVzdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnaW4nKV0pIDogJycScAoGbm90X2luGAcgAygFQmDCSF0KWwoMaW50MzIubm90X2luGkt0aGlzIGluIHJ1bGVzLm5vdF9pbiA/ICdtdXN0IG5vdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW3J1bGVzLm5vdF9pbl0pIDogJycSKwoHZXhhbXBsZRgIIAMoBUIawkgXChUKDWludDMyLmV4YW1wbGUaBHRydWUqCQjoBxCAgICAAkILCglsZXNzX3RoYW5CDgoMZ3JlYXRlcl90aGFuIrAUCgpJbnQ2NFJ1bGVzEn0KBWNvbnN0GAEgASgDQm7CSGsKaQoLaW50NjQuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKEAQoCbHQYAiABKANCdsJIcwpxCghpbnQ2NC5sdBplIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPj0gcnVsZXMubHQ/ICdtdXN0IGJlIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5sdF0pIDogJydIABKVAQoDbHRlGAMgASgDQoUBwkiBAQp/CglpbnQ2NC5sdGUaciFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiB0aGlzID4gcnVsZXMubHRlPyAnbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMubHRlXSkgOiAnJ0gAEvkGCgJndBgEIAEoA0LqBsJI5gYKdAoIaW50NjQuZ3QaaCFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDw9IHJ1bGVzLmd0PyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RdKSA6ICcnCq0BCgtpbnQ2NC5ndF9sdBqdAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKtQEKFWludDY0Lmd0X2x0X2V4Y2x1c2l2ZRqbAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndCAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCr0BCgxpbnQ2NC5ndF9sdGUarAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnCsUBChZpbnQ2NC5ndF9sdGVfZXhjbHVzaXZlGqoBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJydIARLFBwoDZ3RlGAUgASgDQrUHwkixBwqCAQoJaW50NjQuZ3RlGnUhaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8IHJ1bGVzLmd0ZT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZV0pIDogJycKvAEKDGludDY0Lmd0ZV9sdBqrAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3RlICYmICh0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrEAQoWaW50NjQuZ3RlX2x0X2V4Y2x1c2l2ZRqpAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKzAEKDWludDY0Lmd0ZV9sdGUaugFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3RlICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJycK1AEKF2ludDY0Lmd0ZV9sdGVfZXhjbHVzaXZlGrgBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3RlICYmIChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJ0gBEnkKAmluGAYgAygDQm3CSGoKaAoIaW50NjQuaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEnAKBm5vdF9pbhgHIAMoA0JgwkhdClsKDGludDY0Lm5vdF9pbhpLdGhpcyBpbiBydWxlcy5ub3RfaW4gPyAnbXVzdCBub3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtydWxlcy5ub3RfaW5dKSA6ICcnEisKB2V4YW1wbGUYCSADKANCGsJIFwoVCg1pbnQ2NC5leGFtcGxlGgR0cnVlKgkI6AcQgICAgAJCCwoJbGVzc190aGFuQg4KDGdyZWF0ZXJfdGhhbiLCFAoLVUludDMyUnVsZXMSfgoFY29uc3QYASABKA1Cb8JIbApqCgx1aW50MzIuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKFAQoCbHQYAiABKA1Cd8JIdApyCgl1aW50MzIubHQaZSFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiB0aGlzID49IHJ1bGVzLmx0PyAnbXVzdCBiZSBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMubHRdKSA6ICcnSAASlwEKA2x0ZRgDIAEoDUKHAcJIgwEKgAEKCnVpbnQzMi5sdGUaciFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiB0aGlzID4gcnVsZXMubHRlPyAnbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMubHRlXSkgOiAnJ0gAEv4GCgJndBgEIAEoDULvBsJI6wYKdQoJdWludDMyLmd0GmghaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8PSBydWxlcy5ndD8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwquAQoMdWludDMyLmd0X2x0Gp0BaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndCAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwq2AQoWdWludDMyLmd0X2x0X2V4Y2x1c2l2ZRqbAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndCAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCr4BCg11aW50MzIuZ3RfbHRlGqwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrGAQoXdWludDMyLmd0X2x0ZV9leGNsdXNpdmUaqgFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndCAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJ0gBEsoHCgNndGUYBSABKA1CugfCSLYHCoMBCgp1aW50MzIuZ3RlGnUhaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8IHJ1bGVzLmd0ZT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZV0pIDogJycKvQEKDXVpbnQzMi5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKxQEKF3VpbnQzMi5ndGVfbHRfZXhjbHVzaXZlGqkBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrNAQoOdWludDMyLmd0ZV9sdGUaugFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3RlICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJycK1QEKGHVpbnQzMi5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ6CgJpbhgGIAMoDUJuwkhrCmkKCXVpbnQzMi5pbhpcISh0aGlzIGluIGdldEZpZWxkKHJ1bGVzLCAnaW4nKSkgPyAnbXVzdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnaW4nKV0pIDogJycScQoGbm90X2luGAcgAygNQmHCSF4KXAoNdWludDMyLm5vdF9pbhpLdGhpcyBpbiBydWxlcy5ub3RfaW4gPyAnbXVzdCBub3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtydWxlcy5ub3RfaW5dKSA6ICcnEiwKB2V4YW1wbGUYCCADKA1CG8JIGAoWCg51aW50MzIuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4iwhQKC1VJbnQ2NFJ1bGVzEn4KBWNvbnN0GAEgASgEQm/CSGwKagoMdWludDY0LmNvbnN0Glp0aGlzICE9IGdldEZpZWxkKHJ1bGVzLCAnY29uc3QnKSA/ICdtdXN0IGVxdWFsICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnY29uc3QnKV0pIDogJycShQEKAmx0GAIgASgEQnfCSHQKcgoJdWludDY0Lmx0GmUhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+PSBydWxlcy5sdD8gJ211c3QgYmUgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmx0XSkgOiAnJ0gAEpcBCgNsdGUYAyABKARChwHCSIMBCoABCgp1aW50NjQubHRlGnIhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+IHJ1bGVzLmx0ZT8gJ211c3QgYmUgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmx0ZV0pIDogJydIABL+BgoCZ3QYBCABKARC7wbCSOsGCnUKCXVpbnQ2NC5ndBpoIWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmIHRoaXMgPD0gcnVsZXMuZ3Q/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndF0pIDogJycKrgEKDHVpbnQ2NC5ndF9sdBqdAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKtgEKFnVpbnQ2NC5ndF9sdF9leGNsdXNpdmUamwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwq+AQoNdWludDY0Lmd0X2x0ZRqsAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndCAmJiAodGhpcyA+IHJ1bGVzLmx0ZSB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJycKxgEKF3VpbnQ2NC5ndF9sdGVfZXhjbHVzaXZlGqoBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJydIARLKBwoDZ3RlGAUgASgEQroHwki2BwqDAQoKdWludDY0Lmd0ZRp1IWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmIHRoaXMgPCBydWxlcy5ndGU/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGVdKSA6ICcnCr0BCg11aW50NjQuZ3RlX2x0GqsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCsUBChd1aW50NjQuZ3RlX2x0X2V4Y2x1c2l2ZRqpAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKzQEKDnVpbnQ2NC5ndGVfbHRlGroBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+IHJ1bGVzLmx0ZSB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdGVdKSA6ICcnCtUBChh1aW50NjQuZ3RlX2x0ZV9leGNsdXNpdmUauAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdGVdKSA6ICcnSAESegoCaW4YBiADKARCbsJIawppCgl1aW50NjQuaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEnEKBm5vdF9pbhgHIAMoBEJhwkheClwKDXVpbnQ2NC5ub3RfaW4aS3RoaXMgaW4gcnVsZXMubm90X2luID8gJ211c3Qgbm90IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbcnVsZXMubm90X2luXSkgOiAnJxIsCgdleGFtcGxlGAggAygEQhvCSBgKFgoOdWludDY0LmV4YW1wbGUaBHRydWUqCQjoBxCAgICAAkILCglsZXNzX3RoYW5CDgoMZ3JlYXRlcl90aGFuIsIUCgtTSW50MzJSdWxlcxJ+CgVjb25zdBgBIAEoEUJvwkhsCmoKDHNpbnQzMi5jb25zdBpadGhpcyAhPSBnZXRGaWVsZChydWxlcywgJ2NvbnN0JykgPyAnbXVzdCBlcXVhbCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2NvbnN0JyldKSA6ICcnEoUBCgJsdBgCIAEoEUJ3wkh0CnIKCXNpbnQzMi5sdBplIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPj0gcnVsZXMubHQ/ICdtdXN0IGJlIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5sdF0pIDogJydIABKXAQoDbHRlGAMgASgRQocBwkiDAQqAAQoKc2ludDMyLmx0ZRpyIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPiBydWxlcy5sdGU/ICdtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5sdGVdKSA6ICcnSAAS/gYKAmd0GAQgASgRQu8GwkjrBgp1CglzaW50MzIuZ3QaaCFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDw9IHJ1bGVzLmd0PyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RdKSA6ICcnCq4BCgxzaW50MzIuZ3RfbHQanQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ICYmICh0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCrYBChZzaW50MzIuZ3RfbHRfZXhjbHVzaXZlGpsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKvgEKDXNpbnQzMi5ndF9sdGUarAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnCsYBChdzaW50MzIuZ3RfbHRlX2V4Y2x1c2l2ZRqqAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnSAESygcKA2d0ZRgFIAEoEUK6B8JItgcKgwEKCnNpbnQzMi5ndGUadSFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDwgcnVsZXMuZ3RlPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlXSkgOiAnJwq9AQoNc2ludDMyLmd0ZV9sdBqrAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3RlICYmICh0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrFAQoXc2ludDMyLmd0ZV9sdF9leGNsdXNpdmUaqQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3RlICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCs0BCg5zaW50MzIuZ3RlX2x0ZRq6AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJwrVAQoYc2ludDMyLmd0ZV9sdGVfZXhjbHVzaXZlGrgBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3RlICYmIChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJ0gBEnoKAmluGAYgAygRQm7CSGsKaQoJc2ludDMyLmluGlwhKHRoaXMgaW4gZ2V0RmllbGQocnVsZXMsICdpbicpKSA/ICdtdXN0IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdpbicpXSkgOiAnJxJxCgZub3RfaW4YByADKBFCYcJIXgpcCg1zaW50MzIubm90X2luGkt0aGlzIGluIHJ1bGVzLm5vdF9pbiA/ICdtdXN0IG5vdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW3J1bGVzLm5vdF9pbl0pIDogJycSLAoHZXhhbXBsZRgIIAMoEUIbwkgYChYKDnNpbnQzMi5leGFtcGxlGgR0cnVlKgkI6AcQgICAgAJCCwoJbGVzc190aGFuQg4KDGdyZWF0ZXJfdGhhbiLCFAoLU0ludDY0UnVsZXMSfgoFY29uc3QYASABKBJCb8JIbApqCgxzaW50NjQuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKFAQoCbHQYAiABKBJCd8JIdApyCglzaW50NjQubHQaZSFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiB0aGlzID49IHJ1bGVzLmx0PyAnbXVzdCBiZSBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMubHRdKSA6ICcnSAASlwEKA2x0ZRgDIAEoEkKHAcJIgwEKgAEKCnNpbnQ2NC5sdGUaciFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiB0aGlzID4gcnVsZXMubHRlPyAnbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMubHRlXSkgOiAnJ0gAEv4GCgJndBgEIAEoEkLvBsJI6wYKdQoJc2ludDY0Lmd0GmghaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8PSBydWxlcy5ndD8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwquAQoMc2ludDY0Lmd0X2x0Gp0BaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndCAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwq2AQoWc2ludDY0Lmd0X2x0X2V4Y2x1c2l2ZRqbAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndCAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCr4BCg1zaW50NjQuZ3RfbHRlGqwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrGAQoXc2ludDY0Lmd0X2x0ZV9leGNsdXNpdmUaqgFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndCAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJ0gBEsoHCgNndGUYBSABKBJCugfCSLYHCoMBCgpzaW50NjQuZ3RlGnUhaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8IHJ1bGVzLmd0ZT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZV0pIDogJycKvQEKDXNpbnQ2NC5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKxQEKF3NpbnQ2NC5ndGVfbHRfZXhjbHVzaXZlGqkBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrNAQoOc2ludDY0Lmd0ZV9sdGUaugFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3RlICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJycK1QEKGHNpbnQ2NC5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ6CgJpbhgGIAMoEkJuwkhrCmkKCXNpbnQ2NC5pbhpcISh0aGlzIGluIGdldEZpZWxkKHJ1bGVzLCAnaW4nKSkgPyAnbXVzdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnaW4nKV0pIDogJycScQoGbm90X2luGAcgAygSQmHCSF4KXAoNc2ludDY0Lm5vdF9pbhpLdGhpcyBpbiBydWxlcy5ub3RfaW4gPyAnbXVzdCBub3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtydWxlcy5ub3RfaW5dKSA6ICcnEiwKB2V4YW1wbGUYCCADKBJCG8JIGAoWCg5zaW50NjQuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4i0xQKDEZpeGVkMzJSdWxlcxJ/CgVjb25zdBgBIAEoB0JwwkhtCmsKDWZpeGVkMzIuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKGAQoCbHQYAiABKAdCeMJIdQpzCgpmaXhlZDMyLmx0GmUhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+PSBydWxlcy5sdD8gJ211c3QgYmUgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmx0XSkgOiAnJ0gAEpgBCgNsdGUYAyABKAdCiAHCSIQBCoEBCgtmaXhlZDMyLmx0ZRpyIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPiBydWxlcy5sdGU/ICdtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5sdGVdKSA6ICcnSAASgwcKAmd0GAQgASgHQvQGwkjwBgp2CgpmaXhlZDMyLmd0GmghaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8PSBydWxlcy5ndD8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwqvAQoNZml4ZWQzMi5ndF9sdBqdAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKtwEKF2ZpeGVkMzIuZ3RfbHRfZXhjbHVzaXZlGpsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKvwEKDmZpeGVkMzIuZ3RfbHRlGqwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrHAQoYZml4ZWQzMi5ndF9sdGVfZXhjbHVzaXZlGqoBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJydIARLPBwoDZ3RlGAUgASgHQr8Hwki7BwqEAQoLZml4ZWQzMi5ndGUadSFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDwgcnVsZXMuZ3RlPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlXSkgOiAnJwq+AQoOZml4ZWQzMi5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKxgEKGGZpeGVkMzIuZ3RlX2x0X2V4Y2x1c2l2ZRqpAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKzgEKD2ZpeGVkMzIuZ3RlX2x0ZRq6AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJwrWAQoZZml4ZWQzMi5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ7CgJpbhgGIAMoB0JvwkhsCmoKCmZpeGVkMzIuaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEnIKBm5vdF9pbhgHIAMoB0JiwkhfCl0KDmZpeGVkMzIubm90X2luGkt0aGlzIGluIHJ1bGVzLm5vdF9pbiA/ICdtdXN0IG5vdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW3J1bGVzLm5vdF9pbl0pIDogJycSLQoHZXhhbXBsZRgIIAMoB0IcwkgZChcKD2ZpeGVkMzIuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4i0xQKDEZpeGVkNjRSdWxlcxJ/CgVjb25zdBgBIAEoBkJwwkhtCmsKDWZpeGVkNjQuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKGAQoCbHQYAiABKAZCeMJIdQpzCgpmaXhlZDY0Lmx0GmUhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+PSBydWxlcy5sdD8gJ211c3QgYmUgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmx0XSkgOiAnJ0gAEpgBCgNsdGUYAyABKAZCiAHCSIQBCoEBCgtmaXhlZDY0Lmx0ZRpyIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPiBydWxlcy5sdGU/ICdtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5sdGVdKSA6ICcnSAASgwcKAmd0GAQgASgGQvQGwkjwBgp2CgpmaXhlZDY0Lmd0GmghaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8PSBydWxlcy5ndD8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwqvAQoNZml4ZWQ2NC5ndF9sdBqdAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKtwEKF2ZpeGVkNjQuZ3RfbHRfZXhjbHVzaXZlGpsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKvwEKDmZpeGVkNjQuZ3RfbHRlGqwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrHAQoYZml4ZWQ2NC5ndF9sdGVfZXhjbHVzaXZlGqoBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlIDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJydIARLPBwoDZ3RlGAUgASgGQr8Hwki7BwqEAQoLZml4ZWQ2NC5ndGUadSFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDwgcnVsZXMuZ3RlPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlXSkgOiAnJwq+AQoOZml4ZWQ2NC5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKxgEKGGZpeGVkNjQuZ3RlX2x0X2V4Y2x1c2l2ZRqpAWhhcyhydWxlcy5sdCkgJiYgcnVsZXMubHQgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKzgEKD2ZpeGVkNjQuZ3RlX2x0ZRq6AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJwrWAQoZZml4ZWQ2NC5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ7CgJpbhgGIAMoBkJvwkhsCmoKCmZpeGVkNjQuaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEnIKBm5vdF9pbhgHIAMoBkJiwkhfCl0KDmZpeGVkNjQubm90X2luGkt0aGlzIGluIHJ1bGVzLm5vdF9pbiA/ICdtdXN0IG5vdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW3J1bGVzLm5vdF9pbl0pIDogJycSLQoHZXhhbXBsZRgIIAMoBkIcwkgZChcKD2ZpeGVkNjQuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4i5RQKDVNGaXhlZDMyUnVsZXMSgAEKBWNvbnN0GAEgASgPQnHCSG4KbAoOc2ZpeGVkMzIuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKHAQoCbHQYAiABKA9CecJIdgp0CgtzZml4ZWQzMi5sdBplIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPj0gcnVsZXMubHQ/ICdtdXN0IGJlIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5sdF0pIDogJydIABKZAQoDbHRlGAMgASgPQokBwkiFAQqCAQoMc2ZpeGVkMzIubHRlGnIhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+IHJ1bGVzLmx0ZT8gJ211c3QgYmUgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmx0ZV0pIDogJydIABKIBwoCZ3QYBCABKA9C+QbCSPUGCncKC3NmaXhlZDMyLmd0GmghaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8PSBydWxlcy5ndD8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwqwAQoOc2ZpeGVkMzIuZ3RfbHQanQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ICYmICh0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCrgBChhzZml4ZWQzMi5ndF9sdF9leGNsdXNpdmUamwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwrAAQoPc2ZpeGVkMzIuZ3RfbHRlGqwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrIAQoZc2ZpeGVkMzIuZ3RfbHRlX2V4Y2x1c2l2ZRqqAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnSAES1AcKA2d0ZRgFIAEoD0LEB8JIwAcKhQEKDHNmaXhlZDMyLmd0ZRp1IWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmIHRoaXMgPCBydWxlcy5ndGU/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGVdKSA6ICcnCr8BCg9zZml4ZWQzMi5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKxwEKGXNmaXhlZDMyLmd0ZV9sdF9leGNsdXNpdmUaqQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3RlICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCs8BChBzZml4ZWQzMi5ndGVfbHRlGroBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+IHJ1bGVzLmx0ZSB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdGVdKSA6ICcnCtcBChpzZml4ZWQzMi5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ8CgJpbhgGIAMoD0JwwkhtCmsKC3NmaXhlZDMyLmluGlwhKHRoaXMgaW4gZ2V0RmllbGQocnVsZXMsICdpbicpKSA/ICdtdXN0IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdpbicpXSkgOiAnJxJzCgZub3RfaW4YByADKA9CY8JIYApeCg9zZml4ZWQzMi5ub3RfaW4aS3RoaXMgaW4gcnVsZXMubm90X2luID8gJ211c3Qgbm90IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbcnVsZXMubm90X2luXSkgOiAnJxIuCgdleGFtcGxlGAggAygPQh3CSBoKGAoQc2ZpeGVkMzIuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4i5RQKDVNGaXhlZDY0UnVsZXMSgAEKBWNvbnN0GAEgASgQQnHCSG4KbAoOc2ZpeGVkNjQuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKHAQoCbHQYAiABKBBCecJIdgp0CgtzZml4ZWQ2NC5sdBplIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPj0gcnVsZXMubHQ/ICdtdXN0IGJlIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5sdF0pIDogJydIABKZAQoDbHRlGAMgASgQQokBwkiFAQqCAQoMc2ZpeGVkNjQubHRlGnIhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+IHJ1bGVzLmx0ZT8gJ211c3QgYmUgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmx0ZV0pIDogJydIABKIBwoCZ3QYBCABKBBC+QbCSPUGCncKC3NmaXhlZDY0Lmd0GmghaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8PSBydWxlcy5ndD8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0XSkgOiAnJwqwAQoOc2ZpeGVkNjQuZ3RfbHQanQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ICYmICh0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCrgBChhzZml4ZWQ2NC5ndF9sdF9leGNsdXNpdmUamwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3QgJiYgKHJ1bGVzLmx0IDw9IHRoaXMgJiYgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBvciBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwrAAQoPc2ZpeGVkNjQuZ3RfbHRlGqwBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJwrIAQoZc2ZpeGVkNjQuZ3RfbHRlX2V4Y2x1c2l2ZRqqAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnSAES1AcKA2d0ZRgFIAEoEELEB8JIwAcKhQEKDHNmaXhlZDY0Lmd0ZRp1IWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmIHRoaXMgPCBydWxlcy5ndGU/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGVdKSA6ICcnCr8BCg9zZml4ZWQ2NC5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKxwEKGXNmaXhlZDY0Lmd0ZV9sdF9leGNsdXNpdmUaqQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0IDwgcnVsZXMuZ3RlICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCs8BChBzZml4ZWQ2NC5ndGVfbHRlGroBaGFzKHJ1bGVzLmx0ZSkgJiYgcnVsZXMubHRlID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+IHJ1bGVzLmx0ZSB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdGVdKSA6ICcnCtcBChpzZml4ZWQ2NC5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJ8CgJpbhgGIAMoEEJwwkhtCmsKC3NmaXhlZDY0LmluGlwhKHRoaXMgaW4gZ2V0RmllbGQocnVsZXMsICdpbicpKSA/ICdtdXN0IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdpbicpXSkgOiAnJxJzCgZub3RfaW4YByADKBBCY8JIYApeCg9zZml4ZWQ2NC5ub3RfaW4aS3RoaXMgaW4gcnVsZXMubm90X2luID8gJ211c3Qgbm90IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbcnVsZXMubm90X2luXSkgOiAnJxIuCgdleGFtcGxlGAggAygQQh3CSBoKGAoQc2ZpeGVkNjQuZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4iwAEKCUJvb2xSdWxlcxJ8CgVjb25zdBgBIAEoCEJtwkhqCmgKCmJvb2wuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxIqCgdleGFtcGxlGAIgAygIQhnCSBYKFAoMYm9vbC5leGFtcGxlGgR0cnVlKgkI6AcQgICAgAIi6jwKC1N0cmluZ1J1bGVzEoABCgVjb25zdBgBIAEoCUJxwkhuCmwKDHN0cmluZy5jb25zdBpcdGhpcyAhPSBnZXRGaWVsZChydWxlcywgJ2NvbnN0JykgPyAnbXVzdCBlcXVhbCBgJXNgJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnY29uc3QnKV0pIDogJycScQoDbGVuGBMgASgEQmTCSGEKXwoKc3RyaW5nLmxlbhpRdWludCh0aGlzLnNpemUoKSkgIT0gcnVsZXMubGVuID8gJ211c3QgYmUgJXMgY2hhcmFjdGVycycuZm9ybWF0KFtydWxlcy5sZW5dKSA6ICcnEokBCgdtaW5fbGVuGAIgASgEQnjCSHUKcwoOc3RyaW5nLm1pbl9sZW4aYXVpbnQodGhpcy5zaXplKCkpIDwgcnVsZXMubWluX2xlbiA/ICdtdXN0IGJlIGF0IGxlYXN0ICVzIGNoYXJhY3RlcnMnLmZvcm1hdChbcnVsZXMubWluX2xlbl0pIDogJycSiAEKB21heF9sZW4YAyABKARCd8JIdApyCg5zdHJpbmcubWF4X2xlbhpgdWludCh0aGlzLnNpemUoKSkgPiBydWxlcy5tYXhfbGVuID8gJ211c3QgYmUgYXQgbW9zdCAlcyBjaGFyYWN0ZXJzJy5mb3JtYXQoW3J1bGVzLm1heF9sZW5dKSA6ICcnEosBCglsZW5fYnl0ZXMYFCABKARCeMJIdQpzChBzdHJpbmcubGVuX2J5dGVzGl91aW50KGJ5dGVzKHRoaXMpLnNpemUoKSkgIT0gcnVsZXMubGVuX2J5dGVzID8gJ211c3QgYmUgJXMgYnl0ZXMnLmZvcm1hdChbcnVsZXMubGVuX2J5dGVzXSkgOiAnJxKUAQoJbWluX2J5dGVzGAQgASgEQoABwkh9CnsKEHN0cmluZy5taW5fYnl0ZXMaZ3VpbnQoYnl0ZXModGhpcykuc2l6ZSgpKSA8IHJ1bGVzLm1pbl9ieXRlcyA/ICdtdXN0IGJlIGF0IGxlYXN0ICVzIGJ5dGVzJy5mb3JtYXQoW3J1bGVzLm1pbl9ieXRlc10pIDogJycSkgEKCW1heF9ieXRlcxgFIAEoBEJ/wkh8CnoKEHN0cmluZy5tYXhfYnl0ZXMaZnVpbnQoYnl0ZXModGhpcykuc2l6ZSgpKSA+IHJ1bGVzLm1heF9ieXRlcyA/ICdtdXN0IGJlIGF0IG1vc3QgJXMgYnl0ZXMnLmZvcm1hdChbcnVsZXMubWF4X2J5dGVzXSkgOiAnJxKHAQoHcGF0dGVybhgGIAEoCUJ2wkhzCnEKDnN0cmluZy5wYXR0ZXJuGl8hdGhpcy5tYXRjaGVzKHJ1bGVzLnBhdHRlcm4pID8gJ2RvZXMgbm90IG1hdGNoIHJlZ2V4IHBhdHRlcm4gYCVzYCcuZm9ybWF0KFtydWxlcy5wYXR0ZXJuXSkgOiAnJxJ+CgZwcmVmaXgYByABKAlCbsJIawppCg1zdHJpbmcucHJlZml4GlghdGhpcy5zdGFydHNXaXRoKHJ1bGVzLnByZWZpeCkgPyAnZG9lcyBub3QgaGF2ZSBwcmVmaXggYCVzYCcuZm9ybWF0KFtydWxlcy5wcmVmaXhdKSA6ICcnEnwKBnN1ZmZpeBgIIAEoCUJswkhpCmcKDXN0cmluZy5zdWZmaXgaViF0aGlzLmVuZHNXaXRoKHJ1bGVzLnN1ZmZpeCkgPyAnZG9lcyBub3QgaGF2ZSBzdWZmaXggYCVzYCcuZm9ybWF0KFtydWxlcy5zdWZmaXhdKSA6ICcnEooBCghjb250YWlucxgJIAEoCUJ4wkh1CnMKD3N0cmluZy5jb250YWlucxpgIXRoaXMuY29udGFpbnMocnVsZXMuY29udGFpbnMpID8gJ2RvZXMgbm90IGNvbnRhaW4gc3Vic3RyaW5nIGAlc2AnLmZvcm1hdChbcnVsZXMuY29udGFpbnNdKSA6ICcnEpEBCgxub3RfY29udGFpbnMYFyABKAlCe8JIeAp2ChNzdHJpbmcubm90X2NvbnRhaW5zGl90aGlzLmNvbnRhaW5zKHJ1bGVzLm5vdF9jb250YWlucykgPyAnY29udGFpbnMgc3Vic3RyaW5nIGAlc2AnLmZvcm1hdChbcnVsZXMubm90X2NvbnRhaW5zXSkgOiAnJxJ6CgJpbhgKIAMoCUJuwkhrCmkKCXN0cmluZy5pbhpcISh0aGlzIGluIGdldEZpZWxkKHJ1bGVzLCAnaW4nKSkgPyAnbXVzdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnaW4nKV0pIDogJycScQoGbm90X2luGAsgAygJQmHCSF4KXAoNc3RyaW5nLm5vdF9pbhpLdGhpcyBpbiBydWxlcy5ub3RfaW4gPyAnbXVzdCBub3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtydWxlcy5ub3RfaW5dKSA6ICcnEtkBCgVlbWFpbBgMIAEoCELHAcJIwwEKWwoMc3RyaW5nLmVtYWlsEh1tdXN0IGJlIGEgdmFsaWQgZW1haWwgYWRkcmVzcxosIXJ1bGVzLmVtYWlsIHx8IHRoaXMgPT0gJycgfHwgdGhpcy5pc0VtYWlsKCkKZAoSc3RyaW5nLmVtYWlsX2VtcHR5EjJ2YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgZW1haWwgYWRkcmVzcxoaIXJ1bGVzLmVtYWlsIHx8IHRoaXMgIT0gJydIABLhAQoIaG9zdG5hbWUYDSABKAhCzAHCSMgBCl8KD3N0cmluZy5ob3N0bmFtZRIYbXVzdCBiZSBhIHZhbGlkIGhvc3RuYW1lGjIhcnVsZXMuaG9zdG5hbWUgfHwgdGhpcyA9PSAnJyB8fCB0aGlzLmlzSG9zdG5hbWUoKQplChVzdHJpbmcuaG9zdG5hbWVfZW1wdHkSLXZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBob3N0bmFtZRodIXJ1bGVzLmhvc3RuYW1lIHx8IHRoaXMgIT0gJydIABLBAQoCaXAYDiABKAhCsgHCSK4BCk8KCXN0cmluZy5pcBIabXVzdCBiZSBhIHZhbGlkIElQIGFkZHJlc3MaJiFydWxlcy5pcCB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNJcCgpClsKD3N0cmluZy5pcF9lbXB0eRIvdmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIElQIGFkZHJlc3MaFyFydWxlcy5pcCB8fCB0aGlzICE9ICcnSAAS0AEKBGlwdjQYDyABKAhCvwHCSLsBClYKC3N0cmluZy5pcHY0EhxtdXN0IGJlIGEgdmFsaWQgSVB2NCBhZGRyZXNzGikhcnVsZXMuaXB2NCB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNJcCg0KQphChFzdHJpbmcuaXB2NF9lbXB0eRIxdmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIElQdjQgYWRkcmVzcxoZIXJ1bGVzLmlwdjQgfHwgdGhpcyAhPSAnJ0gAEtABCgRpcHY2GBAgASgIQr8Bwki7AQpWCgtzdHJpbmcuaXB2NhIcbXVzdCBiZSBhIHZhbGlkIElQdjYgYWRkcmVzcxopIXJ1bGVzLmlwdjYgfHwgdGhpcyA9PSAnJyB8fCB0aGlzLmlzSXAoNikKYQoRc3RyaW5nLmlwdjZfZW1wdHkSMXZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBJUHY2IGFkZHJlc3MaGSFydWxlcy5pcHY2IHx8IHRoaXMgIT0gJydIABK5AQoDdXJpGBEgASgIQqkBwkilAQpLCgpzdHJpbmcudXJpEhNtdXN0IGJlIGEgdmFsaWQgVVJJGighcnVsZXMudXJpIHx8IHRoaXMgPT0gJycgfHwgdGhpcy5pc1VyaSgpClYKEHN0cmluZy51cmlfZW1wdHkSKHZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBVUkkaGCFydWxlcy51cmkgfHwgdGhpcyAhPSAnJ0gAEmoKB3VyaV9yZWYYEiABKAhCV8JIVApSCg5zdHJpbmcudXJpX3JlZhIdbXVzdCBiZSBhIHZhbGlkIFVSSSBSZWZlcmVuY2UaISFydWxlcy51cmlfcmVmIHx8IHRoaXMuaXNVcmlSZWYoKUgAEokCCgdhZGRyZXNzGBUgASgIQvUBwkjxAQp7Cg5zdHJpbmcuYWRkcmVzcxInbXVzdCBiZSBhIHZhbGlkIGhvc3RuYW1lLCBvciBpcCBhZGRyZXNzGkAhcnVsZXMuYWRkcmVzcyB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNIb3N0bmFtZSgpIHx8IHRoaXMuaXNJcCgpCnIKFHN0cmluZy5hZGRyZXNzX2VtcHR5Ejx2YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgaG9zdG5hbWUsIG9yIGlwIGFkZHJlc3MaHCFydWxlcy5hZGRyZXNzIHx8IHRoaXMgIT0gJydIABKSAgoEdXVpZBgWIAEoCEKBAsJI/QEKnwEKC3N0cmluZy51dWlkEhRtdXN0IGJlIGEgdmFsaWQgVVVJRBp6IXJ1bGVzLnV1aWQgfHwgdGhpcyA9PSAnJyB8fCB0aGlzLm1hdGNoZXMoJ15bMC05YS1mQS1GXXs4fS1bMC05YS1mQS1GXXs0fS1bMC05YS1mQS1GXXs0fS1bMC05YS1mQS1GXXs0fS1bMC05YS1mQS1GXXsxMn0kJykKWQoRc3RyaW5nLnV1aWRfZW1wdHkSKXZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBVVUlEGhkhcnVsZXMudXVpZCB8fCB0aGlzICE9ICcnSAAS6gEKBXR1dWlkGCEgASgIQtgBwkjUAQptCgxzdHJpbmcudHV1aWQSHG11c3QgYmUgYSB2YWxpZCB0cmltbWVkIFVVSUQaPyFydWxlcy50dXVpZCB8fCB0aGlzID09ICcnIHx8IHRoaXMubWF0Y2hlcygnXlswLTlhLWZBLUZdezMyfSQnKQpjChJzdHJpbmcudHV1aWRfZW1wdHkSMXZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCB0cmltbWVkIFVVSUQaGiFydWxlcy50dXVpZCB8fCB0aGlzICE9ICcnSAASkAIKEWlwX3dpdGhfcHJlZml4bGVuGBogASgIQvIBwkjuAQpyChhzdHJpbmcuaXBfd2l0aF9wcmVmaXhsZW4SGW11c3QgYmUgYSB2YWxpZCBJUCBwcmVmaXgaOyFydWxlcy5pcF93aXRoX3ByZWZpeGxlbiB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNJcFByZWZpeCgpCngKHnN0cmluZy5pcF93aXRoX3ByZWZpeGxlbl9lbXB0eRIudmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIElQIHByZWZpeBomIXJ1bGVzLmlwX3dpdGhfcHJlZml4bGVuIHx8IHRoaXMgIT0gJydIABLJAgoTaXB2NF93aXRoX3ByZWZpeGxlbhgbIAEoCEKpAsJIpQIKjQEKGnN0cmluZy5pcHY0X3dpdGhfcHJlZml4bGVuEi9tdXN0IGJlIGEgdmFsaWQgSVB2NCBhZGRyZXNzIHdpdGggcHJlZml4IGxlbmd0aBo+IXJ1bGVzLmlwdjRfd2l0aF9wcmVmaXhsZW4gfHwgdGhpcyA9PSAnJyB8fCB0aGlzLmlzSXBQcmVmaXgoNCkKkgEKIHN0cmluZy5pcHY0X3dpdGhfcHJlZml4bGVuX2VtcHR5EkR2YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgSVB2NCBhZGRyZXNzIHdpdGggcHJlZml4IGxlbmd0aBooIXJ1bGVzLmlwdjRfd2l0aF9wcmVmaXhsZW4gfHwgdGhpcyAhPSAnJ0gAEskCChNpcHY2X3dpdGhfcHJlZml4bGVuGBwgASgIQqkCwkilAgqNAQoac3RyaW5nLmlwdjZfd2l0aF9wcmVmaXhsZW4SL211c3QgYmUgYSB2YWxpZCBJUHY2IGFkZHJlc3Mgd2l0aCBwcmVmaXggbGVuZ3RoGj4hcnVsZXMuaXB2Nl93aXRoX3ByZWZpeGxlbiB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNJcFByZWZpeCg2KQqSAQogc3RyaW5nLmlwdjZfd2l0aF9wcmVmaXhsZW5fZW1wdHkSRHZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBJUHY2IGFkZHJlc3Mgd2l0aCBwcmVmaXggbGVuZ3RoGighcnVsZXMuaXB2Nl93aXRoX3ByZWZpeGxlbiB8fCB0aGlzICE9ICcnSAAS7AEKCWlwX3ByZWZpeBgdIAEoCELWAcJI0gEKZgoQc3RyaW5nLmlwX3ByZWZpeBIZbXVzdCBiZSBhIHZhbGlkIElQIHByZWZpeBo3IXJ1bGVzLmlwX3ByZWZpeCB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNJcFByZWZpeCh0cnVlKQpoChZzdHJpbmcuaXBfcHJlZml4X2VtcHR5Ei52YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgSVAgcHJlZml4Gh4hcnVsZXMuaXBfcHJlZml4IHx8IHRoaXMgIT0gJydIABL9AQoLaXB2NF9wcmVmaXgYHiABKAhC5QHCSOEBCm8KEnN0cmluZy5pcHY0X3ByZWZpeBIbbXVzdCBiZSBhIHZhbGlkIElQdjQgcHJlZml4GjwhcnVsZXMuaXB2NF9wcmVmaXggfHwgdGhpcyA9PSAnJyB8fCB0aGlzLmlzSXBQcmVmaXgoNCwgdHJ1ZSkKbgoYc3RyaW5nLmlwdjRfcHJlZml4X2VtcHR5EjB2YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgSVB2NCBwcmVmaXgaICFydWxlcy5pcHY0X3ByZWZpeCB8fCB0aGlzICE9ICcnSAAS/QEKC2lwdjZfcHJlZml4GB8gASgIQuUBwkjhAQpvChJzdHJpbmcuaXB2Nl9wcmVmaXgSG211c3QgYmUgYSB2YWxpZCBJUHY2IHByZWZpeBo8IXJ1bGVzLmlwdjZfcHJlZml4IHx8IHRoaXMgPT0gJycgfHwgdGhpcy5pc0lwUHJlZml4KDYsIHRydWUpCm4KGHN0cmluZy5pcHY2X3ByZWZpeF9lbXB0eRIwdmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIElQdjYgcHJlZml4GiAhcnVsZXMuaXB2Nl9wcmVmaXggfHwgdGhpcyAhPSAnJ0gAEq8CCg1ob3N0X2FuZF9wb3J0GCAgASgIQpUCwkiRAgqTAQoUc3RyaW5nLmhvc3RfYW5kX3BvcnQSO211c3QgYmUgYSB2YWxpZCBob3N0IChob3N0bmFtZSBvciBJUCBhZGRyZXNzKSBhbmQgcG9ydCBwYWlyGj4hcnVsZXMuaG9zdF9hbmRfcG9ydCB8fCB0aGlzID09ICcnIHx8IHRoaXMuaXNIb3N0QW5kUG9ydCh0cnVlKQp5ChpzdHJpbmcuaG9zdF9hbmRfcG9ydF9lbXB0eRI3dmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIGhvc3QgYW5kIHBvcnQgcGFpchoiIXJ1bGVzLmhvc3RfYW5kX3BvcnQgfHwgdGhpcyAhPSAnJ0gAEu4BCgR1bGlkGCMgASgIQt0BwkjZAQp8CgtzdHJpbmcudWxpZBIUbXVzdCBiZSBhIHZhbGlkIFVMSUQaVyFydWxlcy51bGlkIHx8IHRoaXMgPT0gJycgfHwgdGhpcy5tYXRjaGVzKCdeWzAtN11bMC05QS1ISktNTlAtVFYtWmEtaGprbW5wLXR2LXpdezI1fSQnKQpZChFzdHJpbmcudWxpZF9lbXB0eRIpdmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIFVMSUQaGSFydWxlcy51bGlkIHx8IHRoaXMgIT0gJydIABLUAgoMcHJvdG9idWZfZnFuGCUgASgIQrsCwki3AgqvAQoTc3RyaW5nLnByb3RvYnVmX2ZxbhItbXVzdCBiZSBhIHZhbGlkIGZ1bGx5LXF1YWxpZmllZCBQcm90b2J1ZiBuYW1lGmkhcnVsZXMucHJvdG9idWZfZnFuIHx8IHRoaXMgPT0gJycgfHwgdGhpcy5tYXRjaGVzKCdeW0EtWmEtel9dW0EtWmEtel8wLTldKihcXC5bQS1aYS16X11bQS1aYS16XzAtOV0qKSokJykKggEKGXN0cmluZy5wcm90b2J1Zl9mcW5fZW1wdHkSQnZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBmdWxseS1xdWFsaWZpZWQgUHJvdG9idWYgbmFtZRohIXJ1bGVzLnByb3RvYnVmX2ZxbiB8fCB0aGlzICE9ICcnSAASkQMKEHByb3RvYnVmX2RvdF9mcW4YJiABKAhC9ALCSPACCs0BChdzdHJpbmcucHJvdG9idWZfZG90X2ZxbhJAbXVzdCBiZSBhIHZhbGlkIGZ1bGx5LXF1YWxpZmllZCBQcm90b2J1ZiBuYW1lIHdpdGggYSBsZWFkaW5nIGRvdBpwIXJ1bGVzLnByb3RvYnVmX2RvdF9mcW4gfHwgdGhpcyA9PSAnJyB8fCB0aGlzLm1hdGNoZXMoJ15cXC5bQS1aYS16X11bQS1aYS16XzAtOV0qKFxcLltBLVphLXpfXVtBLVphLXpfMC05XSopKiQnKQqdAQodc3RyaW5nLnByb3RvYnVmX2RvdF9mcW5fZW1wdHkSVXZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBmdWxseS1xdWFsaWZpZWQgUHJvdG9idWYgbmFtZSB3aXRoIGEgbGVhZGluZyBkb3QaJSFydWxlcy5wcm90b2J1Zl9kb3RfZnFuIHx8IHRoaXMgIT0gJydIABKcBQoQd2VsbF9rbm93bl9yZWdleBgYIAEoDjIYLmJ1Zi52YWxpZGF0ZS5Lbm93blJlZ2V4QuUEwkjhBArqAQojc3RyaW5nLndlbGxfa25vd25fcmVnZXguaGVhZGVyX25hbWUSIG11c3QgYmUgYSB2YWxpZCBIVFRQIGhlYWRlciBuYW1lGqABcnVsZXMud2VsbF9rbm93bl9yZWdleCAhPSAxIHx8IHRoaXMgPT0gJycgfHwgdGhpcy5tYXRjaGVzKCFoYXMocnVsZXMuc3RyaWN0KSB8fCBydWxlcy5zdHJpY3QgPydeOj9bMC05YS16QS1aISMkJSZcJyorLS5eX3x+XHg2MF0rJCcgOideW15cdTAwMDBcdTAwMEFcdTAwMERdKyQnKQqNAQopc3RyaW5nLndlbGxfa25vd25fcmVnZXguaGVhZGVyX25hbWVfZW1wdHkSNXZhbHVlIGlzIGVtcHR5LCB3aGljaCBpcyBub3QgYSB2YWxpZCBIVFRQIGhlYWRlciBuYW1lGilydWxlcy53ZWxsX2tub3duX3JlZ2V4ICE9IDEgfHwgdGhpcyAhPSAnJwrhAQokc3RyaW5nLndlbGxfa25vd25fcmVnZXguaGVhZGVyX3ZhbHVlEiFtdXN0IGJlIGEgdmFsaWQgSFRUUCBoZWFkZXIgdmFsdWUalQFydWxlcy53ZWxsX2tub3duX3JlZ2V4ICE9IDIgfHwgdGhpcy5tYXRjaGVzKCFoYXMocnVsZXMuc3RyaWN0KSB8fCBydWxlcy5zdHJpY3QgPydeW15cdTAwMDAtXHUwMDA4XHUwMDBBLVx1MDAxRlx1MDA3Rl0qJCcgOideW15cdTAwMDBcdTAwMEFcdTAwMERdKiQnKUgAEg4KBnN0cmljdBgZIAEoCBIsCgdleGFtcGxlGCIgAygJQhvCSBgKFgoOc3RyaW5nLmV4YW1wbGUaBHRydWUqCQjoBxCAgICAAkIMCgp3ZWxsX2tub3duIt0RCgpCeXRlc1J1bGVzEnoKBWNvbnN0GAEgASgMQmvCSGgKZgoLYnl0ZXMuY29uc3QaV3RoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgYmUgJXgnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxJrCgNsZW4YDSABKARCXsJIWwpZCglieXRlcy5sZW4aTHVpbnQodGhpcy5zaXplKCkpICE9IHJ1bGVzLmxlbiA/ICdtdXN0IGJlICVzIGJ5dGVzJy5mb3JtYXQoW3J1bGVzLmxlbl0pIDogJycSgwEKB21pbl9sZW4YAiABKARCcsJIbwptCg1ieXRlcy5taW5fbGVuGlx1aW50KHRoaXMuc2l6ZSgpKSA8IHJ1bGVzLm1pbl9sZW4gPyAnbXVzdCBiZSBhdCBsZWFzdCAlcyBieXRlcycuZm9ybWF0KFtydWxlcy5taW5fbGVuXSkgOiAnJxKCAQoHbWF4X2xlbhgDIAEoBEJxwkhuCmwKDWJ5dGVzLm1heF9sZW4aW3VpbnQodGhpcy5zaXplKCkpID4gcnVsZXMubWF4X2xlbiA/ICdtdXN0IGJlIGF0IG1vc3QgJXMgYnl0ZXMnLmZvcm1hdChbcnVsZXMubWF4X2xlbl0pIDogJycSigEKB3BhdHRlcm4YBCABKAlCecJIdgp0Cg1ieXRlcy5wYXR0ZXJuGmMhc3RyaW5nKHRoaXMpLm1hdGNoZXMocnVsZXMucGF0dGVybikgPyAnbXVzdCBtYXRjaCByZWdleCBwYXR0ZXJuIGAlc2AnLmZvcm1hdChbcnVsZXMucGF0dGVybl0pIDogJycSewoGcHJlZml4GAUgASgMQmvCSGgKZgoMYnl0ZXMucHJlZml4GlYhdGhpcy5zdGFydHNXaXRoKHJ1bGVzLnByZWZpeCkgPyAnZG9lcyBub3QgaGF2ZSBwcmVmaXggJXgnLmZvcm1hdChbcnVsZXMucHJlZml4XSkgOiAnJxJ5CgZzdWZmaXgYBiABKAxCacJIZgpkCgxieXRlcy5zdWZmaXgaVCF0aGlzLmVuZHNXaXRoKHJ1bGVzLnN1ZmZpeCkgPyAnZG9lcyBub3QgaGF2ZSBzdWZmaXggJXgnLmZvcm1hdChbcnVsZXMuc3VmZml4XSkgOiAnJxJ9Cghjb250YWlucxgHIAEoDEJrwkhoCmYKDmJ5dGVzLmNvbnRhaW5zGlQhdGhpcy5jb250YWlucyhydWxlcy5jb250YWlucykgPyAnZG9lcyBub3QgY29udGFpbiAleCcuZm9ybWF0KFtydWxlcy5jb250YWluc10pIDogJycSoQEKAmluGAggAygMQpQBwkiQAQqNAQoIYnl0ZXMuaW4agAFnZXRGaWVsZChydWxlcywgJ2luJykuc2l6ZSgpID4gMCAmJiAhKHRoaXMgaW4gZ2V0RmllbGQocnVsZXMsICdpbicpKSA/ICdtdXN0IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdpbicpXSkgOiAnJxJwCgZub3RfaW4YCSADKAxCYMJIXQpbCgxieXRlcy5ub3RfaW4aS3RoaXMgaW4gcnVsZXMubm90X2luID8gJ211c3Qgbm90IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbcnVsZXMubm90X2luXSkgOiAnJxLlAQoCaXAYCiABKAhC1gHCSNIBCm4KCGJ5dGVzLmlwEhptdXN0IGJlIGEgdmFsaWQgSVAgYWRkcmVzcxpGIXJ1bGVzLmlwIHx8IHRoaXMuc2l6ZSgpID09IDAgfHwgdGhpcy5zaXplKCkgPT0gNCB8fCB0aGlzLnNpemUoKSA9PSAxNgpgCg5ieXRlcy5pcF9lbXB0eRIvdmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIElQIGFkZHJlc3MaHSFydWxlcy5pcCB8fCB0aGlzLnNpemUoKSAhPSAwSAAS3gEKBGlwdjQYCyABKAhCzQHCSMkBCl8KCmJ5dGVzLmlwdjQSHG11c3QgYmUgYSB2YWxpZCBJUHY0IGFkZHJlc3MaMyFydWxlcy5pcHY0IHx8IHRoaXMuc2l6ZSgpID09IDAgfHwgdGhpcy5zaXplKCkgPT0gNApmChBieXRlcy5pcHY0X2VtcHR5EjF2YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgSVB2NCBhZGRyZXNzGh8hcnVsZXMuaXB2NCB8fCB0aGlzLnNpemUoKSAhPSAwSAAS3wEKBGlwdjYYDCABKAhCzgHCSMoBCmAKCmJ5dGVzLmlwdjYSHG11c3QgYmUgYSB2YWxpZCBJUHY2IGFkZHJlc3MaNCFydWxlcy5pcHY2IHx8IHRoaXMuc2l6ZSgpID09IDAgfHwgdGhpcy5zaXplKCkgPT0gMTYKZgoQYnl0ZXMuaXB2Nl9lbXB0eRIxdmFsdWUgaXMgZW1wdHksIHdoaWNoIGlzIG5vdCBhIHZhbGlkIElQdjYgYWRkcmVzcxofIXJ1bGVzLmlwdjYgfHwgdGhpcy5zaXplKCkgIT0gMEgAEs8BCgR1dWlkGA8gASgIQr4Bwki6AQpYCgpieXRlcy51dWlkEhRtdXN0IGJlIGEgdmFsaWQgVVVJRBo0IXJ1bGVzLnV1aWQgfHwgdGhpcy5zaXplKCkgPT0gMCB8fCB0aGlzLnNpemUoKSA9PSAxNgpeChBieXRlcy51dWlkX2VtcHR5Eil2YWx1ZSBpcyBlbXB0eSwgd2hpY2ggaXMgbm90IGEgdmFsaWQgVVVJRBofIXJ1bGVzLnV1aWQgfHwgdGhpcy5zaXplKCkgIT0gMEgAEisKB2V4YW1wbGUYDiADKAxCGsJIFwoVCg1ieXRlcy5leGFtcGxlGgR0cnVlKgkI6AcQgICAgAJCDAoKd2VsbF9rbm93biLBAwoJRW51bVJ1bGVzEnwKBWNvbnN0GAEgASgFQm3CSGoKaAoKZW51bS5jb25zdBpadGhpcyAhPSBnZXRGaWVsZChydWxlcywgJ2NvbnN0JykgPyAnbXVzdCBlcXVhbCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2NvbnN0JyldKSA6ICcnEhQKDGRlZmluZWRfb25seRgCIAEoCBJ4CgJpbhgDIAMoBUJswkhpCmcKB2VudW0uaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEm8KBm5vdF9pbhgEIAMoBUJfwkhcCloKC2VudW0ubm90X2luGkt0aGlzIGluIHJ1bGVzLm5vdF9pbiA/ICdtdXN0IG5vdCBiZSBpbiBsaXN0ICVzJy5mb3JtYXQoW3J1bGVzLm5vdF9pbl0pIDogJycSKgoHZXhhbXBsZRgFIAMoBUIZwkgWChQKDGVudW0uZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACIu0DCg1SZXBlYXRlZFJ1bGVzEpYBCgltaW5faXRlbXMYASABKARCggHCSH8KfQoScmVwZWF0ZWQubWluX2l0ZW1zGmd1aW50KHRoaXMuc2l6ZSgpKSA8IHJ1bGVzLm1pbl9pdGVtcyA/ICdtdXN0IGNvbnRhaW4gYXQgbGVhc3QgJWQgaXRlbShzKScuZm9ybWF0KFtydWxlcy5taW5faXRlbXNdKSA6ICcnEpwBCgltYXhfaXRlbXMYAiABKARCiAHCSIQBCoEBChJyZXBlYXRlZC5tYXhfaXRlbXMaa3VpbnQodGhpcy5zaXplKCkpID4gcnVsZXMubWF4X2l0ZW1zID8gJ211c3QgY29udGFpbiBubyBtb3JlIHRoYW4gJXMgaXRlbShzKScuZm9ybWF0KFtydWxlcy5tYXhfaXRlbXNdKSA6ICcnEnAKBnVuaXF1ZRgDIAEoCEJgwkhdClsKD3JlcGVhdGVkLnVuaXF1ZRIocmVwZWF0ZWQgdmFsdWUgbXVzdCBjb250YWluIHVuaXF1ZSBpdGVtcxoeIXJ1bGVzLnVuaXF1ZSB8fCB0aGlzLnVuaXF1ZSgpEicKBWl0ZW1zGAQgASgLMhguYnVmLnZhbGlkYXRlLkZpZWxkUnVsZXMqCQjoBxCAgICAAiKKAwoITWFwUnVsZXMSjwEKCW1pbl9wYWlycxgBIAEoBEJ8wkh5CncKDW1hcC5taW5fcGFpcnMaZnVpbnQodGhpcy5zaXplKCkpIDwgcnVsZXMubWluX3BhaXJzID8gJ21hcCBtdXN0IGJlIGF0IGxlYXN0ICVkIGVudHJpZXMnLmZvcm1hdChbcnVsZXMubWluX3BhaXJzXSkgOiAnJxKOAQoJbWF4X3BhaXJzGAIgASgEQnvCSHgKdgoNbWFwLm1heF9wYWlycxpldWludCh0aGlzLnNpemUoKSkgPiBydWxlcy5tYXhfcGFpcnMgPyAnbWFwIG11c3QgYmUgYXQgbW9zdCAlZCBlbnRyaWVzJy5mb3JtYXQoW3J1bGVzLm1heF9wYWlyc10pIDogJycSJgoEa2V5cxgEIAEoCzIYLmJ1Zi52YWxpZGF0ZS5GaWVsZFJ1bGVzEigKBnZhbHVlcxgFIAEoCzIYLmJ1Zi52YWxpZGF0ZS5GaWVsZFJ1bGVzKgkI6AcQgICAgAIiJgoIQW55UnVsZXMSCgoCaW4YAiADKAkSDgoGbm90X2luGAMgAygJIr8WCg1EdXJhdGlvblJ1bGVzEpsBCgVjb25zdBgCIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkJxwkhuCmwKDmR1cmF0aW9uLmNvbnN0Glp0aGlzICE9IGdldEZpZWxkKHJ1bGVzLCAnY29uc3QnKSA/ICdtdXN0IGVxdWFsICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnY29uc3QnKV0pIDogJycSogEKAmx0GAMgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uQnnCSHYKdAoLZHVyYXRpb24ubHQaZSFoYXMocnVsZXMuZ3RlKSAmJiAhaGFzKHJ1bGVzLmd0KSAmJiB0aGlzID49IHJ1bGVzLmx0PyAnbXVzdCBiZSBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMubHRdKSA6ICcnSAAStAEKA2x0ZRgEIAEoCzIZLmdvb2dsZS5wcm90b2J1Zi5EdXJhdGlvbkKJAcJIhQEKggEKDGR1cmF0aW9uLmx0ZRpyIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPiBydWxlcy5sdGU/ICdtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5sdGVdKSA6ICcnSAASowcKAmd0GAUgASgLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uQvkGwkj1Bgp3CgtkdXJhdGlvbi5ndBpoIWhhcyhydWxlcy5sdCkgJiYgIWhhcyhydWxlcy5sdGUpICYmIHRoaXMgPD0gcnVsZXMuZ3Q/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndF0pIDogJycKsAEKDmR1cmF0aW9uLmd0X2x0Gp0BaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndCAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0XSkgOiAnJwq4AQoYZHVyYXRpb24uZ3RfbHRfZXhjbHVzaXZlGpsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKwAEKD2R1cmF0aW9uLmd0X2x0ZRqsAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndCAmJiAodGhpcyA+IHJ1bGVzLmx0ZSB8fCB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIGFuZCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3QsIHJ1bGVzLmx0ZV0pIDogJycKyAEKGWR1cmF0aW9uLmd0X2x0ZV9leGNsdXNpdmUaqgFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndCAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDw9IHJ1bGVzLmd0KT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRlXSkgOiAnJ0gBEu8HCgNndGUYBiABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25CxAfCSMAHCoUBCgxkdXJhdGlvbi5ndGUadSFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDwgcnVsZXMuZ3RlPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlXSkgOiAnJwq/AQoPZHVyYXRpb24uZ3RlX2x0GqsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPj0gcnVsZXMubHQgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRdKSA6ICcnCscBChlkdXJhdGlvbi5ndGVfbHRfZXhjbHVzaXZlGqkBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrPAQoQZHVyYXRpb24uZ3RlX2x0ZRq6AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA+PSBydWxlcy5ndGUgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZSwgcnVsZXMubHRlXSkgOiAnJwrXAQoaZHVyYXRpb24uZ3RlX2x0ZV9leGNsdXNpdmUauAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPCBydWxlcy5ndGUgJiYgKHJ1bGVzLmx0ZSA8IHRoaXMgJiYgdGhpcyA8IHJ1bGVzLmd0ZSk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAlcyBvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdGVdKSA6ICcnSAESlwEKAmluGAcgAygLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uQnDCSG0KawoLZHVyYXRpb24uaW4aXCEodGhpcyBpbiBnZXRGaWVsZChydWxlcywgJ2luJykpID8gJ211c3QgYmUgaW4gbGlzdCAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEo4BCgZub3RfaW4YCCADKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25CY8JIYApeCg9kdXJhdGlvbi5ub3RfaW4aS3RoaXMgaW4gcnVsZXMubm90X2luID8gJ211c3Qgbm90IGJlIGluIGxpc3QgJXMnLmZvcm1hdChbcnVsZXMubm90X2luXSkgOiAnJxJJCgdleGFtcGxlGAkgAygLMhkuZ29vZ2xlLnByb3RvYnVmLkR1cmF0aW9uQh3CSBoKGAoQZHVyYXRpb24uZXhhbXBsZRoEdHJ1ZSoJCOgHEICAgIACQgsKCWxlc3NfdGhhbkIOCgxncmVhdGVyX3RoYW4i6wUKDkZpZWxkTWFza1J1bGVzErkBCgVjb25zdBgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE1hc2tCjQHCSIkBCoYBChBmaWVsZF9tYXNrLmNvbnN0GnJ0aGlzLnBhdGhzICE9IGdldEZpZWxkKHJ1bGVzLCAnY29uc3QnKS5wYXRocyA/ICdtdXN0IGVxdWFsIHBhdGhzICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnY29uc3QnKS5wYXRoc10pIDogJycS0wEKAmluGAIgAygJQsYBwkjCAQq/AQoNZmllbGRfbWFzay5pbhqtASF0aGlzLnBhdGhzLmFsbChwLCBwIGluIGdldEZpZWxkKHJ1bGVzLCAnaW4nKSB8fCBnZXRGaWVsZChydWxlcywgJ2luJykuZXhpc3RzKGYsIHAuc3RhcnRzV2l0aChmKycuJykpKSA/ICdtdXN0IG9ubHkgY29udGFpbiBwYXRocyBpbiAlcycuZm9ybWF0KFtnZXRGaWVsZChydWxlcywgJ2luJyldKSA6ICcnEu0BCgZub3RfaW4YAyADKAlC3AHCSNgBCtUBChFmaWVsZF9tYXNrLm5vdF9pbhq/ASF0aGlzLnBhdGhzLmFsbChwLCAhKHAgaW4gZ2V0RmllbGQocnVsZXMsICdub3RfaW4nKSB8fCBnZXRGaWVsZChydWxlcywgJ25vdF9pbicpLmV4aXN0cyhmLCBwLnN0YXJ0c1dpdGgoZisnLicpKSkpID8gJ211c3Qgbm90IGNvbnRhaW4gYW55IHBhdGhzIGluICVzJy5mb3JtYXQoW2dldEZpZWxkKHJ1bGVzLCAnbm90X2luJyldKSA6ICcnEkwKB2V4YW1wbGUYBCADKAsyGi5nb29nbGUucHJvdG9idWYuRmllbGRNYXNrQh/CSBwKGgoSZmllbGRfbWFzay5leGFtcGxlGgR0cnVlKgkI6AcQgICAgAIisBcKDlRpbWVzdGFtcFJ1bGVzEp0BCgVjb25zdBgCIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCcsJIbwptCg90aW1lc3RhbXAuY29uc3QaWnRoaXMgIT0gZ2V0RmllbGQocnVsZXMsICdjb25zdCcpID8gJ211c3QgZXF1YWwgJXMnLmZvcm1hdChbZ2V0RmllbGQocnVsZXMsICdjb25zdCcpXSkgOiAnJxKkAQoCbHQYAyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQnrCSHcKdQoMdGltZXN0YW1wLmx0GmUhaGFzKHJ1bGVzLmd0ZSkgJiYgIWhhcyhydWxlcy5ndCkgJiYgdGhpcyA+PSBydWxlcy5sdD8gJ211c3QgYmUgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmx0XSkgOiAnJ0gAErYBCgNsdGUYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQooBwkiGAQqDAQoNdGltZXN0YW1wLmx0ZRpyIWhhcyhydWxlcy5ndGUpICYmICFoYXMocnVsZXMuZ3QpICYmIHRoaXMgPiBydWxlcy5sdGU/ICdtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5sdGVdKSA6ICcnSAASZgoGbHRfbm93GAcgASgIQlTCSFEKTwoQdGltZXN0YW1wLmx0X25vdxo7KHJ1bGVzLmx0X25vdyAmJiB0aGlzID4gbm93KSA/ICdtdXN0IGJlIGxlc3MgdGhhbiBub3cnIDogJydIABKpBwoCZ3QYBSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQv4Gwkj6Bgp4Cgx0aW1lc3RhbXAuZ3QaaCFoYXMocnVsZXMubHQpICYmICFoYXMocnVsZXMubHRlKSAmJiB0aGlzIDw9IHJ1bGVzLmd0PyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RdKSA6ICcnCrEBCg90aW1lc3RhbXAuZ3RfbHQanQFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ICYmICh0aGlzID49IHJ1bGVzLmx0IHx8IHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgYW5kIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndCwgcnVsZXMubHRdKSA6ICcnCrkBChl0aW1lc3RhbXAuZ3RfbHRfZXhjbHVzaXZlGpsBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdCA8PSB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdF0pIDogJycKwQEKEHRpbWVzdGFtcC5ndF9sdGUarAFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3QgJiYgKHRoaXMgPiBydWxlcy5sdGUgfHwgdGhpcyA8PSBydWxlcy5ndCk/ICdtdXN0IGJlIGdyZWF0ZXIgdGhhbiAlcyBhbmQgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnCskBChp0aW1lc3RhbXAuZ3RfbHRlX2V4Y2x1c2l2ZRqqAWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ICYmIChydWxlcy5sdGUgPCB0aGlzICYmIHRoaXMgPD0gcnVsZXMuZ3QpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gJXMgb3IgbGVzcyB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0LCBydWxlcy5sdGVdKSA6ICcnSAES9QcKA2d0ZRgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCyQfCSMUHCoYBCg10aW1lc3RhbXAuZ3RlGnUhaGFzKHJ1bGVzLmx0KSAmJiAhaGFzKHJ1bGVzLmx0ZSkgJiYgdGhpcyA8IHJ1bGVzLmd0ZT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzJy5mb3JtYXQoW3J1bGVzLmd0ZV0pIDogJycKwAEKEHRpbWVzdGFtcC5ndGVfbHQaqwFoYXMocnVsZXMubHQpICYmIHJ1bGVzLmx0ID49IHJ1bGVzLmd0ZSAmJiAodGhpcyA+PSBydWxlcy5sdCB8fCB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIGFuZCBsZXNzIHRoYW4gJXMnLmZvcm1hdChbcnVsZXMuZ3RlLCBydWxlcy5sdF0pIDogJycKyAEKGnRpbWVzdGFtcC5ndGVfbHRfZXhjbHVzaXZlGqkBaGFzKHJ1bGVzLmx0KSAmJiBydWxlcy5sdCA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHQgPD0gdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0XSkgOiAnJwrQAQoRdGltZXN0YW1wLmd0ZV9sdGUaugFoYXMocnVsZXMubHRlKSAmJiBydWxlcy5sdGUgPj0gcnVsZXMuZ3RlICYmICh0aGlzID4gcnVsZXMubHRlIHx8IHRoaXMgPCBydWxlcy5ndGUpPyAnbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gJXMgYW5kIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJycK2AEKG3RpbWVzdGFtcC5ndGVfbHRlX2V4Y2x1c2l2ZRq4AWhhcyhydWxlcy5sdGUpICYmIHJ1bGVzLmx0ZSA8IHJ1bGVzLmd0ZSAmJiAocnVsZXMubHRlIDwgdGhpcyAmJiB0aGlzIDwgcnVsZXMuZ3RlKT8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvICVzIG9yIGxlc3MgdGhhbiBvciBlcXVhbCB0byAlcycuZm9ybWF0KFtydWxlcy5ndGUsIHJ1bGVzLmx0ZV0pIDogJydIARJpCgZndF9ub3cYCCABKAhCV8JIVApSChB0aW1lc3RhbXAuZ3Rfbm93Gj4ocnVsZXMuZ3Rfbm93ICYmIHRoaXMgPCBub3cpID8gJ211c3QgYmUgZ3JlYXRlciB0aGFuIG5vdycgOiAnJ0gBErEBCgZ3aXRoaW4YCSABKAsyGS5nb29nbGUucHJvdG9idWYuRHVyYXRpb25ChQHCSIEBCn8KEHRpbWVzdGFtcC53aXRoaW4aa3RoaXMgPCBub3ctcnVsZXMud2l0aGluIHx8IHRoaXMgPiBub3crcnVsZXMud2l0aGluID8gJ211c3QgYmUgd2l0aGluICVzIG9mIG5vdycuZm9ybWF0KFtydWxlcy53aXRoaW5dKSA6ICcnEksKB2V4YW1wbGUYCiADKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQh7CSBsKGQoRdGltZXN0YW1wLmV4YW1wbGUaBHRydWUqCQjoBxCAgICAAkILCglsZXNzX3RoYW5CDgoMZ3JlYXRlcl90aGFuIjkKClZpb2xhdGlvbnMSKwoKdmlvbGF0aW9ucxgBIAMoCzIXLmJ1Zi52YWxpZGF0ZS5WaW9sYXRpb24inwEKCVZpb2xhdGlvbhImCgVmaWVsZBgFIAEoCzIXLmJ1Zi52YWxpZGF0ZS5GaWVsZFBhdGgSJQoEcnVsZRgGIAEoCzIXLmJ1Zi52YWxpZGF0ZS5GaWVsZFBhdGgSDwoHcnVsZV9pZBgCIAEoCRIPCgdtZXNzYWdlGAMgASgJEg8KB2Zvcl9rZXkYBCABKAhKBAgBEAJSCmZpZWxkX3BhdGgiPQoJRmllbGRQYXRoEjAKCGVsZW1lbnRzGAEgAygLMh4uYnVmLnZhbGlkYXRlLkZpZWxkUGF0aEVsZW1lbnQi6QIKEEZpZWxkUGF0aEVsZW1lbnQSFAoMZmllbGRfbnVtYmVyGAEgASgFEhIKCmZpZWxkX25hbWUYAiABKAkSPgoKZmllbGRfdHlwZRgDIAEoDjIqLmdvb2dsZS5wcm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90by5UeXBlEjwKCGtleV90eXBlGAQgASgOMiouZ29vZ2xlLnByb3RvYnVmLkZpZWxkRGVzY3JpcHRvclByb3RvLlR5cGUSPgoKdmFsdWVfdHlwZRgFIAEoDjIqLmdvb2dsZS5wcm90b2J1Zi5GaWVsZERlc2NyaXB0b3JQcm90by5UeXBlEg8KBWluZGV4GAYgASgESAASEgoIYm9vbF9rZXkYByABKAhIABIRCgdpbnRfa2V5GAggASgDSAASEgoIdWludF9rZXkYCSABKARIABIUCgpzdHJpbmdfa2V5GAogASgJSABCCwoJc3Vic2NyaXB0KqEBCgZJZ25vcmUSFgoSSUdOT1JFX1VOU1BFQ0lGSUVEEAASGAoUSUdOT1JFX0lGX1pFUk9fVkFMVUUQARIRCg1JR05PUkVfQUxXQVlTEAMiBAgCEAIqDElHTk9SRV9FTVBUWSoOSUdOT1JFX0RFRkFVTFQqF0lHTk9SRV9JRl9ERUZBVUxUX1ZBTFVFKhVJR05PUkVfSUZfVU5QT1BVTEFURUQqbgoKS25vd25SZWdleBIbChdLTk9XTl9SRUdFWF9VTlNQRUNJRklFRBAAEiAKHEtOT1dOX1JFR0VYX0hUVFBfSEVBREVSX05BTUUQARIhCh1LTk9XTl9SRUdFWF9IVFRQX0hFQURFUl9WQUxVRRACOlYKB21lc3NhZ2USHy5nb29nbGUucHJvdG9idWYuTWVzc2FnZU9wdGlvbnMYhwkgASgLMhouYnVmLnZhbGlkYXRlLk1lc3NhZ2VSdWxlc1IHbWVzc2FnZTpOCgVvbmVvZhIdLmdvb2dsZS5wcm90b2J1Zi5PbmVvZk9wdGlvbnMYhwkgASgLMhguYnVmLnZhbGlkYXRlLk9uZW9mUnVsZXNSBW9uZW9mOk4KBWZpZWxkEh0uZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucxiHCSABKAsyGC5idWYudmFsaWRhdGUuRmllbGRSdWxlc1IFZmllbGQ6XQoKcHJlZGVmaW5lZBIdLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMYiAkgASgLMh0uYnVmLnZhbGlkYXRlLlByZWRlZmluZWRSdWxlc1IKcHJlZGVmaW5lZEJuChJidWlsZC5idWYudmFsaWRhdGVCDVZhbGlkYXRlUHJvdG9QAVpHYnVmLmJ1aWxkL2dlbi9nby9idWZidWlsZC9wcm90b3ZhbGlkYXRlL3Byb3RvY29sYnVmZmVycy9nby9idWYvdmFsaWRhdGU", [file_google_protobuf_descriptor, file_google_protobuf_duration, file_google_protobuf_field_mask, file_google_protobuf_timestamp]); + +/** + * `Rule` represents a validation rule written in the Common Expression + * Language (CEL) syntax. Each Rule includes a unique identifier, an + * optional error message, and the CEL expression to evaluate. For more + * information, [see our documentation](https://protovalidate.com/schemas/custom-rules/). + * + * ```proto + * message Foo { + * option (buf.validate.message).cel = { + * id: "foo.bar" + * message: "bar must be greater than 0" + * expression: "this.bar > 0" + * }; + * int32 bar = 1; + * } + * ``` + * + * @generated from message buf.validate.Rule + */ +export type Rule = Message<"buf.validate.Rule"> & { + /** + * `id` is a string that serves as a machine-readable name for this Rule. + * It should be unique within its scope, which could be either a message or a field. + * + * @generated from field: optional string id = 1; + */ + id: string; + + /** + * `message` is an optional field that provides a human-readable error message + * for this Rule when the CEL expression evaluates to false. If a + * non-empty message is provided, any strings resulting from the CEL + * expression evaluation are ignored. + * + * @generated from field: optional string message = 2; + */ + message: string; + + /** + * `expression` is the actual CEL expression that will be evaluated for + * validation. This string must resolve to either a boolean or a string + * value. If the expression evaluates to false or a non-empty string, the + * validation is considered failed, and the message is rejected. + * + * @generated from field: optional string expression = 3; + */ + expression: string; +}; + +/** + * Describes the message buf.validate.Rule. + * Use `create(RuleSchema)` to create a new message. + */ +export const RuleSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 0); + +/** + * MessageRules represents validation rules that are applied to the entire message. + * It includes disabling options and a list of Rule messages representing Common Expression Language (CEL) validation rules. + * + * @generated from message buf.validate.MessageRules + */ +export type MessageRules = Message<"buf.validate.MessageRules"> & { + /** + * `cel_expression` is a repeated field CEL expressions. Each expression specifies a validation + * rule to be applied to this message. These rules are written in Common Expression Language (CEL) syntax. + * + * This is a simplified form of the `cel` Rule field, where only `expression` is set. This allows for + * simpler syntax when defining CEL Rules where `id` and `message` derived from the `expression`. `id` will + * be same as the `expression`. + * + * For more information, [see our documentation](https://protovalidate.com/schemas/custom-rules/). + * + * ```proto + * message MyMessage { + * // The field `foo` must be greater than 42. + * option (buf.validate.message).cel_expression = "this.foo > 42"; + * // The field `foo` must be less than 84. + * option (buf.validate.message).cel_expression = "this.foo < 84"; + * optional int32 foo = 1; + * } + * ``` + * + * @generated from field: repeated string cel_expression = 5; + */ + celExpression: string[]; + + /** + * `cel` is a repeated field of type Rule. Each Rule specifies a validation rule to be applied to this message. + * These rules are written in Common Expression Language (CEL) syntax. For more information, + * [see our documentation](https://protovalidate.com/schemas/custom-rules/). + * + * + * ```proto + * message MyMessage { + * // The field `foo` must be greater than 42. + * option (buf.validate.message).cel = { + * id: "my_message.value", + * message: "must be greater than 42", + * expression: "this.foo > 42", + * }; + * optional int32 foo = 1; + * } + * ``` + * + * @generated from field: repeated buf.validate.Rule cel = 3; + */ + cel: Rule[]; + + /** + * `oneof` is a repeated field of type MessageOneofRule that specifies a list of fields + * of which at most one can be present. If `required` is also specified, then exactly one + * of the specified fields _must_ be present. + * + * This will enforce oneof-like constraints with a few features not provided by + * actual Protobuf oneof declarations: + * 1. Repeated and map fields are allowed in this validation. In a Protobuf oneof, + * only scalar fields are allowed. + * 2. Fields with implicit presence are allowed. In a Protobuf oneof, all member + * fields have explicit presence. This means that, for the purpose of determining + * how many fields are set, explicitly setting such a field to its zero value is + * effectively the same as not setting it at all. + * 3. This will always generate validation errors for a message unmarshalled from + * serialized data that sets more than one field. With a Protobuf oneof, when + * multiple fields are present in the serialized form, earlier values are usually + * silently ignored when unmarshalling, with only the last field being set when + * unmarshalling completes. + * + * Note that adding a field to a `oneof` will also set the IGNORE_IF_ZERO_VALUE on the fields. This means + * only the field that is set will be validated and the unset fields are not validated according to the field rules. + * This behavior can be overridden by setting `ignore` against a field. + * + * ```proto + * message MyMessage { + * // Only one of `field1` or `field2` _can_ be present in this message. + * option (buf.validate.message).oneof = { fields: ["field1", "field2"] }; + * // Exactly one of `field3` or `field4` _must_ be present in this message. + * option (buf.validate.message).oneof = { fields: ["field3", "field4"], required: true }; + * string field1 = 1; + * bytes field2 = 2; + * bool field3 = 3; + * int32 field4 = 4; + * } + * ``` + * + * @generated from field: repeated buf.validate.MessageOneofRule oneof = 4; + */ + oneof: MessageOneofRule[]; +}; + +/** + * Describes the message buf.validate.MessageRules. + * Use `create(MessageRulesSchema)` to create a new message. + */ +export const MessageRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 1); + +/** + * @generated from message buf.validate.MessageOneofRule + */ +export type MessageOneofRule = Message<"buf.validate.MessageOneofRule"> & { + /** + * A list of field names to include in the oneof. All field names must be + * defined in the message. At least one field must be specified, and + * duplicates are not permitted. + * + * @generated from field: repeated string fields = 1; + */ + fields: string[]; + + /** + * If true, one of the fields specified _must_ be set. + * + * @generated from field: optional bool required = 2; + */ + required: boolean; +}; + +/** + * Describes the message buf.validate.MessageOneofRule. + * Use `create(MessageOneofRuleSchema)` to create a new message. + */ +export const MessageOneofRuleSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 2); + +/** + * The `OneofRules` message type enables you to manage rules for + * oneof fields in your protobuf messages. + * + * @generated from message buf.validate.OneofRules + */ +export type OneofRules = Message<"buf.validate.OneofRules"> & { + /** + * If `required` is true, exactly one field of the oneof must be set. A + * validation error is returned if no fields in the oneof are set. Further rules + * should be placed on the fields themselves to ensure they are valid values, + * such as `min_len` or `gt`. + * + * ```proto + * message MyMessage { + * oneof value { + * // Either `a` or `b` must be set. If `a` is set, it must also be + * // non-empty; whereas if `b` is set, it can still be an empty string. + * option (buf.validate.oneof).required = true; + * string a = 1 [(buf.validate.field).string.min_len = 1]; + * string b = 2; + * } + * } + * ``` + * + * @generated from field: optional bool required = 1; + */ + required: boolean; +}; + +/** + * Describes the message buf.validate.OneofRules. + * Use `create(OneofRulesSchema)` to create a new message. + */ +export const OneofRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 3); + +/** + * FieldRules encapsulates the rules for each type of field. Depending on + * the field, the correct set should be used to ensure proper validations. + * + * @generated from message buf.validate.FieldRules + */ +export type FieldRules = Message<"buf.validate.FieldRules"> & { + /** + * `cel_expression` is a repeated field CEL expressions. Each expression specifies a validation + * rule to be applied to this message. These rules are written in Common Expression Language (CEL) syntax. + * + * This is a simplified form of the `cel` Rule field, where only `expression` is set. This allows for + * simpler syntax when defining CEL Rules where `id` and `message` derived from the `expression`. `id` will + * be same as the `expression`. + * + * For more information, [see our documentation](https://protovalidate.com/schemas/custom-rules/). + * + * ```proto + * message MyMessage { + * // The field `value` must be greater than 42. + * optional int32 value = 1 [(buf.validate.field).cel_expression = "this > 42"]; + * } + * ``` + * + * @generated from field: repeated string cel_expression = 29; + */ + celExpression: string[]; + + /** + * `cel` is a repeated field used to represent a textual expression + * in the Common Expression Language (CEL) syntax. For more information, + * [see our documentation](https://protovalidate.com/schemas/custom-rules/). + * + * ```proto + * message MyMessage { + * // The field `value` must be greater than 42. + * optional int32 value = 1 [(buf.validate.field).cel = { + * id: "my_message.value", + * message: "must be greater than 42", + * expression: "this > 42", + * }]; + * } + * ``` + * + * @generated from field: repeated buf.validate.Rule cel = 23; + */ + cel: Rule[]; + + /** + * If `required` is true, the field must be set. A validation error is returned + * if the field is not set. + * + * ```proto + * syntax="proto3"; + * + * message FieldsWithPresence { + * // Requires any string to be set, including the empty string. + * optional string link = 1 [ + * (buf.validate.field).required = true + * ]; + * // Requires true or false to be set. + * optional bool disabled = 2 [ + * (buf.validate.field).required = true + * ]; + * // Requires a message to be set, including the empty message. + * SomeMessage msg = 4 [ + * (buf.validate.field).required = true + * ]; + * } + * ``` + * + * All fields in the example above track presence. By default, Protovalidate + * ignores rules on those fields if no value is set. `required` ensures that + * the fields are set and valid. + * + * Fields that don't track presence are always validated by Protovalidate, + * whether they are set or not. It is not necessary to add `required`. It + * can be added to indicate that the field cannot be the zero value. + * + * ```proto + * syntax="proto3"; + * + * message FieldsWithoutPresence { + * // `string.email` always applies, even to an empty string. + * string link = 1 [ + * (buf.validate.field).string.email = true + * ]; + * // `repeated.min_items` always applies, even to an empty list. + * repeated string labels = 2 [ + * (buf.validate.field).repeated.min_items = 1 + * ]; + * // `required`, for fields that don't track presence, indicates + * // the value of the field can't be the zero value. + * int32 zero_value_not_allowed = 3 [ + * (buf.validate.field).required = true + * ]; + * } + * ``` + * + * To learn which fields track presence, see the + * [Field Presence cheat sheet](https://protobuf.dev/programming-guides/field_presence/#cheat). + * + * Note: While field rules can be applied to repeated items, map keys, and map + * values, the elements are always considered to be set. Consequently, + * specifying `repeated.items.required` is redundant. + * + * @generated from field: optional bool required = 25; + */ + required: boolean; + + /** + * Ignore validation rules on the field if its value matches the specified + * criteria. See the `Ignore` enum for details. + * + * ```proto + * message UpdateRequest { + * // The uri rule only applies if the field is not an empty string. + * string url = 1 [ + * (buf.validate.field).ignore = IGNORE_IF_ZERO_VALUE, + * (buf.validate.field).string.uri = true + * ]; + * } + * ``` + * + * @generated from field: optional buf.validate.Ignore ignore = 27; + */ + ignore: Ignore; + + /** + * @generated from oneof buf.validate.FieldRules.type + */ + type: { + /** + * Scalar Field Types + * + * @generated from field: buf.validate.FloatRules float = 1; + */ + value: FloatRules; + case: "float"; + } | { + /** + * @generated from field: buf.validate.DoubleRules double = 2; + */ + value: DoubleRules; + case: "double"; + } | { + /** + * @generated from field: buf.validate.Int32Rules int32 = 3; + */ + value: Int32Rules; + case: "int32"; + } | { + /** + * @generated from field: buf.validate.Int64Rules int64 = 4; + */ + value: Int64Rules; + case: "int64"; + } | { + /** + * @generated from field: buf.validate.UInt32Rules uint32 = 5; + */ + value: UInt32Rules; + case: "uint32"; + } | { + /** + * @generated from field: buf.validate.UInt64Rules uint64 = 6; + */ + value: UInt64Rules; + case: "uint64"; + } | { + /** + * @generated from field: buf.validate.SInt32Rules sint32 = 7; + */ + value: SInt32Rules; + case: "sint32"; + } | { + /** + * @generated from field: buf.validate.SInt64Rules sint64 = 8; + */ + value: SInt64Rules; + case: "sint64"; + } | { + /** + * @generated from field: buf.validate.Fixed32Rules fixed32 = 9; + */ + value: Fixed32Rules; + case: "fixed32"; + } | { + /** + * @generated from field: buf.validate.Fixed64Rules fixed64 = 10; + */ + value: Fixed64Rules; + case: "fixed64"; + } | { + /** + * @generated from field: buf.validate.SFixed32Rules sfixed32 = 11; + */ + value: SFixed32Rules; + case: "sfixed32"; + } | { + /** + * @generated from field: buf.validate.SFixed64Rules sfixed64 = 12; + */ + value: SFixed64Rules; + case: "sfixed64"; + } | { + /** + * @generated from field: buf.validate.BoolRules bool = 13; + */ + value: BoolRules; + case: "bool"; + } | { + /** + * @generated from field: buf.validate.StringRules string = 14; + */ + value: StringRules; + case: "string"; + } | { + /** + * @generated from field: buf.validate.BytesRules bytes = 15; + */ + value: BytesRules; + case: "bytes"; + } | { + /** + * Complex Field Types + * + * @generated from field: buf.validate.EnumRules enum = 16; + */ + value: EnumRules; + case: "enum"; + } | { + /** + * @generated from field: buf.validate.RepeatedRules repeated = 18; + */ + value: RepeatedRules; + case: "repeated"; + } | { + /** + * @generated from field: buf.validate.MapRules map = 19; + */ + value: MapRules; + case: "map"; + } | { + /** + * Well-Known Field Types + * + * @generated from field: buf.validate.AnyRules any = 20; + */ + value: AnyRules; + case: "any"; + } | { + /** + * @generated from field: buf.validate.DurationRules duration = 21; + */ + value: DurationRules; + case: "duration"; + } | { + /** + * @generated from field: buf.validate.FieldMaskRules field_mask = 28; + */ + value: FieldMaskRules; + case: "fieldMask"; + } | { + /** + * @generated from field: buf.validate.TimestampRules timestamp = 22; + */ + value: TimestampRules; + case: "timestamp"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message buf.validate.FieldRules. + * Use `create(FieldRulesSchema)` to create a new message. + */ +export const FieldRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 4); + +/** + * PredefinedRules are custom rules that can be re-used with + * multiple fields. + * + * @generated from message buf.validate.PredefinedRules + */ +export type PredefinedRules = Message<"buf.validate.PredefinedRules"> & { + /** + * `cel` is a repeated field used to represent a textual expression + * in the Common Expression Language (CEL) syntax. For more information, + * [see our documentation](https://protovalidate.com/schemas/predefined-rules/). + * + * ```proto + * message MyMessage { + * // The field `value` must be greater than 42. + * optional int32 value = 1 [(buf.validate.predefined).cel = { + * id: "my_message.value", + * message: "must be greater than 42", + * expression: "this > 42", + * }]; + * } + * ``` + * + * @generated from field: repeated buf.validate.Rule cel = 1; + */ + cel: Rule[]; +}; + +/** + * Describes the message buf.validate.PredefinedRules. + * Use `create(PredefinedRulesSchema)` to create a new message. + */ +export const PredefinedRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 5); + +/** + * FloatRules describes the rules applied to `float` values. These + * rules may also be applied to the `google.protobuf.FloatValue` Well-Known-Type. + * + * @generated from message buf.validate.FloatRules + */ +export type FloatRules = Message<"buf.validate.FloatRules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyFloat { + * // value must equal 42.0 + * float value = 1 [(buf.validate.field).float.const = 42.0]; + * } + * ``` + * + * @generated from field: optional float const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.FloatRules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyFloat { + * // must be less than 10.0 + * float value = 1 [(buf.validate.field).float.lt = 10.0]; + * } + * ``` + * + * @generated from field: float lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyFloat { + * // must be less than or equal to 10.0 + * float value = 1 [(buf.validate.field).float.lte = 10.0]; + * } + * ``` + * + * @generated from field: float lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.FloatRules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyFloat { + * // must be greater than 5.0 [float.gt] + * float value = 1 [(buf.validate.field).float.gt = 5.0]; + * + * // must be greater than 5 and less than 10.0 [float.gt_lt] + * float other_value = 2 [(buf.validate.field).float = { gt: 5.0, lt: 10.0 }]; + * + * // must be greater than 10 or less than 5.0 [float.gt_lt_exclusive] + * float another_value = 3 [(buf.validate.field).float = { gt: 10.0, lt: 5.0 }]; + * } + * ``` + * + * @generated from field: float gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyFloat { + * // must be greater than or equal to 5.0 [float.gte] + * float value = 1 [(buf.validate.field).float.gte = 5.0]; + * + * // must be greater than or equal to 5.0 and less than 10.0 [float.gte_lt] + * float other_value = 2 [(buf.validate.field).float = { gte: 5.0, lt: 10.0 }]; + * + * // must be greater than or equal to 10.0 or less than 5.0 [float.gte_lt_exclusive] + * float another_value = 3 [(buf.validate.field).float = { gte: 10.0, lt: 5.0 }]; + * } + * ``` + * + * @generated from field: float gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message + * is generated. + * + * ```proto + * message MyFloat { + * // must be in list [1.0, 2.0, 3.0] + * float value = 1 [(buf.validate.field).float = { in: [1.0, 2.0, 3.0] }]; + * } + * ``` + * + * @generated from field: repeated float in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyFloat { + * // value must not be in list [1.0, 2.0, 3.0] + * float value = 1 [(buf.validate.field).float = { not_in: [1.0, 2.0, 3.0] }]; + * } + * ``` + * + * @generated from field: repeated float not_in = 7; + */ + notIn: number[]; + + /** + * `finite` requires the field value to be finite. If the field value is + * infinite or NaN, an error message is generated. + * + * @generated from field: optional bool finite = 8; + */ + finite: boolean; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyFloat { + * float value = 1 [ + * (buf.validate.field).float.example = 1.0, + * (buf.validate.field).float.example = inf + * ]; + * } + * ``` + * + * @generated from field: repeated float example = 9; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.FloatRules. + * Use `create(FloatRulesSchema)` to create a new message. + */ +export const FloatRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 6); + +/** + * DoubleRules describes the rules applied to `double` values. These + * rules may also be applied to the `google.protobuf.DoubleValue` Well-Known-Type. + * + * @generated from message buf.validate.DoubleRules + */ +export type DoubleRules = Message<"buf.validate.DoubleRules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyDouble { + * // value must equal 42.0 + * double value = 1 [(buf.validate.field).double.const = 42.0]; + * } + * ``` + * + * @generated from field: optional double const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.DoubleRules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyDouble { + * // must be less than 10.0 + * double value = 1 [(buf.validate.field).double.lt = 10.0]; + * } + * ``` + * + * @generated from field: double lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified value + * (field <= value). If the field value is greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyDouble { + * // must be less than or equal to 10.0 + * double value = 1 [(buf.validate.field).double.lte = 10.0]; + * } + * ``` + * + * @generated from field: double lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.DoubleRules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or `lte`, + * the range is reversed, and the field value must be outside the specified + * range. If the field value doesn't meet the required conditions, an error + * message is generated. + * + * ```proto + * message MyDouble { + * // must be greater than 5.0 [double.gt] + * double value = 1 [(buf.validate.field).double.gt = 5.0]; + * + * // must be greater than 5 and less than 10.0 [double.gt_lt] + * double other_value = 2 [(buf.validate.field).double = { gt: 5.0, lt: 10.0 }]; + * + * // must be greater than 10 or less than 5.0 [double.gt_lt_exclusive] + * double another_value = 3 [(buf.validate.field).double = { gt: 10.0, lt: 5.0 }]; + * } + * ``` + * + * @generated from field: double gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyDouble { + * // must be greater than or equal to 5.0 [double.gte] + * double value = 1 [(buf.validate.field).double.gte = 5.0]; + * + * // must be greater than or equal to 5.0 and less than 10.0 [double.gte_lt] + * double other_value = 2 [(buf.validate.field).double = { gte: 5.0, lt: 10.0 }]; + * + * // must be greater than or equal to 10.0 or less than 5.0 [double.gte_lt_exclusive] + * double another_value = 3 [(buf.validate.field).double = { gte: 10.0, lt: 5.0 }]; + * } + * ``` + * + * @generated from field: double gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MyDouble { + * // must be in list [1.0, 2.0, 3.0] + * double value = 1 [(buf.validate.field).double = { in: [1.0, 2.0, 3.0] }]; + * } + * ``` + * + * @generated from field: repeated double in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyDouble { + * // value must not be in list [1.0, 2.0, 3.0] + * double value = 1 [(buf.validate.field).double = { not_in: [1.0, 2.0, 3.0] }]; + * } + * ``` + * + * @generated from field: repeated double not_in = 7; + */ + notIn: number[]; + + /** + * `finite` requires the field value to be finite. If the field value is + * infinite or NaN, an error message is generated. + * + * @generated from field: optional bool finite = 8; + */ + finite: boolean; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyDouble { + * double value = 1 [ + * (buf.validate.field).double.example = 1.0, + * (buf.validate.field).double.example = inf + * ]; + * } + * ``` + * + * @generated from field: repeated double example = 9; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.DoubleRules. + * Use `create(DoubleRulesSchema)` to create a new message. + */ +export const DoubleRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 7); + +/** + * Int32Rules describes the rules applied to `int32` values. These + * rules may also be applied to the `google.protobuf.Int32Value` Well-Known-Type. + * + * @generated from message buf.validate.Int32Rules + */ +export type Int32Rules = Message<"buf.validate.Int32Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyInt32 { + * // value must equal 42 + * int32 value = 1 [(buf.validate.field).int32.const = 42]; + * } + * ``` + * + * @generated from field: optional int32 const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.Int32Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field + * < value). If the field value is equal to or greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyInt32 { + * // must be less than 10 + * int32 value = 1 [(buf.validate.field).int32.lt = 10]; + * } + * ``` + * + * @generated from field: int32 lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyInt32 { + * // must be less than or equal to 10 + * int32 value = 1 [(buf.validate.field).int32.lte = 10]; + * } + * ``` + * + * @generated from field: int32 lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.Int32Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyInt32 { + * // must be greater than 5 [int32.gt] + * int32 value = 1 [(buf.validate.field).int32.gt = 5]; + * + * // must be greater than 5 and less than 10 [int32.gt_lt] + * int32 other_value = 2 [(buf.validate.field).int32 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [int32.gt_lt_exclusive] + * int32 another_value = 3 [(buf.validate.field).int32 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: int32 gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified value + * (exclusive). If the value of `gte` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyInt32 { + * // must be greater than or equal to 5 [int32.gte] + * int32 value = 1 [(buf.validate.field).int32.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [int32.gte_lt] + * int32 other_value = 2 [(buf.validate.field).int32 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [int32.gte_lt_exclusive] + * int32 another_value = 3 [(buf.validate.field).int32 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: int32 gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MyInt32 { + * // must be in list [1, 2, 3] + * int32 value = 1 [(buf.validate.field).int32 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated int32 in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error message + * is generated. + * + * ```proto + * message MyInt32 { + * // value must not be in list [1, 2, 3] + * int32 value = 1 [(buf.validate.field).int32 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated int32 not_in = 7; + */ + notIn: number[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyInt32 { + * int32 value = 1 [ + * (buf.validate.field).int32.example = 1, + * (buf.validate.field).int32.example = -10 + * ]; + * } + * ``` + * + * @generated from field: repeated int32 example = 8; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.Int32Rules. + * Use `create(Int32RulesSchema)` to create a new message. + */ +export const Int32RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 8); + +/** + * Int64Rules describes the rules applied to `int64` values. These + * rules may also be applied to the `google.protobuf.Int64Value` Well-Known-Type. + * + * @generated from message buf.validate.Int64Rules + */ +export type Int64Rules = Message<"buf.validate.Int64Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyInt64 { + * // value must equal 42 + * int64 value = 1 [(buf.validate.field).int64.const = 42]; + * } + * ``` + * + * @generated from field: optional int64 const = 1; + */ + const: bigint; + + /** + * @generated from oneof buf.validate.Int64Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyInt64 { + * // must be less than 10 + * int64 value = 1 [(buf.validate.field).int64.lt = 10]; + * } + * ``` + * + * @generated from field: int64 lt = 2; + */ + value: bigint; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyInt64 { + * // must be less than or equal to 10 + * int64 value = 1 [(buf.validate.field).int64.lte = 10]; + * } + * ``` + * + * @generated from field: int64 lte = 3; + */ + value: bigint; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.Int64Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyInt64 { + * // must be greater than 5 [int64.gt] + * int64 value = 1 [(buf.validate.field).int64.gt = 5]; + * + * // must be greater than 5 and less than 10 [int64.gt_lt] + * int64 other_value = 2 [(buf.validate.field).int64 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [int64.gt_lt_exclusive] + * int64 another_value = 3 [(buf.validate.field).int64 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: int64 gt = 4; + */ + value: bigint; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyInt64 { + * // must be greater than or equal to 5 [int64.gte] + * int64 value = 1 [(buf.validate.field).int64.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [int64.gte_lt] + * int64 other_value = 2 [(buf.validate.field).int64 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [int64.gte_lt_exclusive] + * int64 another_value = 3 [(buf.validate.field).int64 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: int64 gte = 5; + */ + value: bigint; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MyInt64 { + * // must be in list [1, 2, 3] + * int64 value = 1 [(buf.validate.field).int64 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated int64 in = 6; + */ + in: bigint[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyInt64 { + * // value must not be in list [1, 2, 3] + * int64 value = 1 [(buf.validate.field).int64 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated int64 not_in = 7; + */ + notIn: bigint[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyInt64 { + * int64 value = 1 [ + * (buf.validate.field).int64.example = 1, + * (buf.validate.field).int64.example = -10 + * ]; + * } + * ``` + * + * @generated from field: repeated int64 example = 9; + */ + example: bigint[]; +}; + +/** + * Describes the message buf.validate.Int64Rules. + * Use `create(Int64RulesSchema)` to create a new message. + */ +export const Int64RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 9); + +/** + * UInt32Rules describes the rules applied to `uint32` values. These + * rules may also be applied to the `google.protobuf.UInt32Value` Well-Known-Type. + * + * @generated from message buf.validate.UInt32Rules + */ +export type UInt32Rules = Message<"buf.validate.UInt32Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyUInt32 { + * // value must equal 42 + * uint32 value = 1 [(buf.validate.field).uint32.const = 42]; + * } + * ``` + * + * @generated from field: optional uint32 const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.UInt32Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyUInt32 { + * // must be less than 10 + * uint32 value = 1 [(buf.validate.field).uint32.lt = 10]; + * } + * ``` + * + * @generated from field: uint32 lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyUInt32 { + * // must be less than or equal to 10 + * uint32 value = 1 [(buf.validate.field).uint32.lte = 10]; + * } + * ``` + * + * @generated from field: uint32 lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.UInt32Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyUInt32 { + * // must be greater than 5 [uint32.gt] + * uint32 value = 1 [(buf.validate.field).uint32.gt = 5]; + * + * // must be greater than 5 and less than 10 [uint32.gt_lt] + * uint32 other_value = 2 [(buf.validate.field).uint32 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [uint32.gt_lt_exclusive] + * uint32 another_value = 3 [(buf.validate.field).uint32 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: uint32 gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyUInt32 { + * // must be greater than or equal to 5 [uint32.gte] + * uint32 value = 1 [(buf.validate.field).uint32.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [uint32.gte_lt] + * uint32 other_value = 2 [(buf.validate.field).uint32 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [uint32.gte_lt_exclusive] + * uint32 another_value = 3 [(buf.validate.field).uint32 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: uint32 gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MyUInt32 { + * // must be in list [1, 2, 3] + * uint32 value = 1 [(buf.validate.field).uint32 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated uint32 in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyUInt32 { + * // value must not be in list [1, 2, 3] + * uint32 value = 1 [(buf.validate.field).uint32 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated uint32 not_in = 7; + */ + notIn: number[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyUInt32 { + * uint32 value = 1 [ + * (buf.validate.field).uint32.example = 1, + * (buf.validate.field).uint32.example = 10 + * ]; + * } + * ``` + * + * @generated from field: repeated uint32 example = 8; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.UInt32Rules. + * Use `create(UInt32RulesSchema)` to create a new message. + */ +export const UInt32RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 10); + +/** + * UInt64Rules describes the rules applied to `uint64` values. These + * rules may also be applied to the `google.protobuf.UInt64Value` Well-Known-Type. + * + * @generated from message buf.validate.UInt64Rules + */ +export type UInt64Rules = Message<"buf.validate.UInt64Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyUInt64 { + * // value must equal 42 + * uint64 value = 1 [(buf.validate.field).uint64.const = 42]; + * } + * ``` + * + * @generated from field: optional uint64 const = 1; + */ + const: bigint; + + /** + * @generated from oneof buf.validate.UInt64Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyUInt64 { + * // must be less than 10 + * uint64 value = 1 [(buf.validate.field).uint64.lt = 10]; + * } + * ``` + * + * @generated from field: uint64 lt = 2; + */ + value: bigint; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyUInt64 { + * // must be less than or equal to 10 + * uint64 value = 1 [(buf.validate.field).uint64.lte = 10]; + * } + * ``` + * + * @generated from field: uint64 lte = 3; + */ + value: bigint; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.UInt64Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyUInt64 { + * // must be greater than 5 [uint64.gt] + * uint64 value = 1 [(buf.validate.field).uint64.gt = 5]; + * + * // must be greater than 5 and less than 10 [uint64.gt_lt] + * uint64 other_value = 2 [(buf.validate.field).uint64 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [uint64.gt_lt_exclusive] + * uint64 another_value = 3 [(buf.validate.field).uint64 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: uint64 gt = 4; + */ + value: bigint; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyUInt64 { + * // must be greater than or equal to 5 [uint64.gte] + * uint64 value = 1 [(buf.validate.field).uint64.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [uint64.gte_lt] + * uint64 other_value = 2 [(buf.validate.field).uint64 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [uint64.gte_lt_exclusive] + * uint64 another_value = 3 [(buf.validate.field).uint64 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: uint64 gte = 5; + */ + value: bigint; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MyUInt64 { + * // must be in list [1, 2, 3] + * uint64 value = 1 [(buf.validate.field).uint64 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated uint64 in = 6; + */ + in: bigint[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyUInt64 { + * // value must not be in list [1, 2, 3] + * uint64 value = 1 [(buf.validate.field).uint64 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated uint64 not_in = 7; + */ + notIn: bigint[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyUInt64 { + * uint64 value = 1 [ + * (buf.validate.field).uint64.example = 1, + * (buf.validate.field).uint64.example = 10 + * ]; + * } + * ``` + * + * @generated from field: repeated uint64 example = 8; + */ + example: bigint[]; +}; + +/** + * Describes the message buf.validate.UInt64Rules. + * Use `create(UInt64RulesSchema)` to create a new message. + */ +export const UInt64RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 11); + +/** + * SInt32Rules describes the rules applied to `sint32` values. + * + * @generated from message buf.validate.SInt32Rules + */ +export type SInt32Rules = Message<"buf.validate.SInt32Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MySInt32 { + * // value must equal 42 + * sint32 value = 1 [(buf.validate.field).sint32.const = 42]; + * } + * ``` + * + * @generated from field: optional sint32 const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.SInt32Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field + * < value). If the field value is equal to or greater than the specified + * value, an error message is generated. + * + * ```proto + * message MySInt32 { + * // must be less than 10 + * sint32 value = 1 [(buf.validate.field).sint32.lt = 10]; + * } + * ``` + * + * @generated from field: sint32 lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MySInt32 { + * // must be less than or equal to 10 + * sint32 value = 1 [(buf.validate.field).sint32.lte = 10]; + * } + * ``` + * + * @generated from field: sint32 lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.SInt32Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySInt32 { + * // must be greater than 5 [sint32.gt] + * sint32 value = 1 [(buf.validate.field).sint32.gt = 5]; + * + * // must be greater than 5 and less than 10 [sint32.gt_lt] + * sint32 other_value = 2 [(buf.validate.field).sint32 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [sint32.gt_lt_exclusive] + * sint32 another_value = 3 [(buf.validate.field).sint32 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sint32 gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySInt32 { + * // must be greater than or equal to 5 [sint32.gte] + * sint32 value = 1 [(buf.validate.field).sint32.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [sint32.gte_lt] + * sint32 other_value = 2 [(buf.validate.field).sint32 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [sint32.gte_lt_exclusive] + * sint32 another_value = 3 [(buf.validate.field).sint32 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sint32 gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MySInt32 { + * // must be in list [1, 2, 3] + * sint32 value = 1 [(buf.validate.field).sint32 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sint32 in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MySInt32 { + * // value must not be in list [1, 2, 3] + * sint32 value = 1 [(buf.validate.field).sint32 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sint32 not_in = 7; + */ + notIn: number[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MySInt32 { + * sint32 value = 1 [ + * (buf.validate.field).sint32.example = 1, + * (buf.validate.field).sint32.example = -10 + * ]; + * } + * ``` + * + * @generated from field: repeated sint32 example = 8; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.SInt32Rules. + * Use `create(SInt32RulesSchema)` to create a new message. + */ +export const SInt32RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 12); + +/** + * SInt64Rules describes the rules applied to `sint64` values. + * + * @generated from message buf.validate.SInt64Rules + */ +export type SInt64Rules = Message<"buf.validate.SInt64Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MySInt64 { + * // value must equal 42 + * sint64 value = 1 [(buf.validate.field).sint64.const = 42]; + * } + * ``` + * + * @generated from field: optional sint64 const = 1; + */ + const: bigint; + + /** + * @generated from oneof buf.validate.SInt64Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field + * < value). If the field value is equal to or greater than the specified + * value, an error message is generated. + * + * ```proto + * message MySInt64 { + * // must be less than 10 + * sint64 value = 1 [(buf.validate.field).sint64.lt = 10]; + * } + * ``` + * + * @generated from field: sint64 lt = 2; + */ + value: bigint; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MySInt64 { + * // must be less than or equal to 10 + * sint64 value = 1 [(buf.validate.field).sint64.lte = 10]; + * } + * ``` + * + * @generated from field: sint64 lte = 3; + */ + value: bigint; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.SInt64Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySInt64 { + * // must be greater than 5 [sint64.gt] + * sint64 value = 1 [(buf.validate.field).sint64.gt = 5]; + * + * // must be greater than 5 and less than 10 [sint64.gt_lt] + * sint64 other_value = 2 [(buf.validate.field).sint64 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [sint64.gt_lt_exclusive] + * sint64 another_value = 3 [(buf.validate.field).sint64 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sint64 gt = 4; + */ + value: bigint; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySInt64 { + * // must be greater than or equal to 5 [sint64.gte] + * sint64 value = 1 [(buf.validate.field).sint64.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [sint64.gte_lt] + * sint64 other_value = 2 [(buf.validate.field).sint64 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [sint64.gte_lt_exclusive] + * sint64 another_value = 3 [(buf.validate.field).sint64 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sint64 gte = 5; + */ + value: bigint; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message + * is generated. + * + * ```proto + * message MySInt64 { + * // must be in list [1, 2, 3] + * sint64 value = 1 [(buf.validate.field).sint64 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sint64 in = 6; + */ + in: bigint[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MySInt64 { + * // value must not be in list [1, 2, 3] + * sint64 value = 1 [(buf.validate.field).sint64 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sint64 not_in = 7; + */ + notIn: bigint[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MySInt64 { + * sint64 value = 1 [ + * (buf.validate.field).sint64.example = 1, + * (buf.validate.field).sint64.example = -10 + * ]; + * } + * ``` + * + * @generated from field: repeated sint64 example = 8; + */ + example: bigint[]; +}; + +/** + * Describes the message buf.validate.SInt64Rules. + * Use `create(SInt64RulesSchema)` to create a new message. + */ +export const SInt64RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 13); + +/** + * Fixed32Rules describes the rules applied to `fixed32` values. + * + * @generated from message buf.validate.Fixed32Rules + */ +export type Fixed32Rules = Message<"buf.validate.Fixed32Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. + * If the field value doesn't match, an error message is generated. + * + * ```proto + * message MyFixed32 { + * // value must equal 42 + * fixed32 value = 1 [(buf.validate.field).fixed32.const = 42]; + * } + * ``` + * + * @generated from field: optional fixed32 const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.Fixed32Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyFixed32 { + * // must be less than 10 + * fixed32 value = 1 [(buf.validate.field).fixed32.lt = 10]; + * } + * ``` + * + * @generated from field: fixed32 lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyFixed32 { + * // must be less than or equal to 10 + * fixed32 value = 1 [(buf.validate.field).fixed32.lte = 10]; + * } + * ``` + * + * @generated from field: fixed32 lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.Fixed32Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyFixed32 { + * // must be greater than 5 [fixed32.gt] + * fixed32 value = 1 [(buf.validate.field).fixed32.gt = 5]; + * + * // must be greater than 5 and less than 10 [fixed32.gt_lt] + * fixed32 other_value = 2 [(buf.validate.field).fixed32 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [fixed32.gt_lt_exclusive] + * fixed32 another_value = 3 [(buf.validate.field).fixed32 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: fixed32 gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyFixed32 { + * // must be greater than or equal to 5 [fixed32.gte] + * fixed32 value = 1 [(buf.validate.field).fixed32.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [fixed32.gte_lt] + * fixed32 other_value = 2 [(buf.validate.field).fixed32 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [fixed32.gte_lt_exclusive] + * fixed32 another_value = 3 [(buf.validate.field).fixed32 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: fixed32 gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message + * is generated. + * + * ```proto + * message MyFixed32 { + * // must be in list [1, 2, 3] + * fixed32 value = 1 [(buf.validate.field).fixed32 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated fixed32 in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyFixed32 { + * // value must not be in list [1, 2, 3] + * fixed32 value = 1 [(buf.validate.field).fixed32 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated fixed32 not_in = 7; + */ + notIn: number[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyFixed32 { + * fixed32 value = 1 [ + * (buf.validate.field).fixed32.example = 1, + * (buf.validate.field).fixed32.example = 2 + * ]; + * } + * ``` + * + * @generated from field: repeated fixed32 example = 8; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.Fixed32Rules. + * Use `create(Fixed32RulesSchema)` to create a new message. + */ +export const Fixed32RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 14); + +/** + * Fixed64Rules describes the rules applied to `fixed64` values. + * + * @generated from message buf.validate.Fixed64Rules + */ +export type Fixed64Rules = Message<"buf.validate.Fixed64Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyFixed64 { + * // value must equal 42 + * fixed64 value = 1 [(buf.validate.field).fixed64.const = 42]; + * } + * ``` + * + * @generated from field: optional fixed64 const = 1; + */ + const: bigint; + + /** + * @generated from oneof buf.validate.Fixed64Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MyFixed64 { + * // must be less than 10 + * fixed64 value = 1 [(buf.validate.field).fixed64.lt = 10]; + * } + * ``` + * + * @generated from field: fixed64 lt = 2; + */ + value: bigint; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MyFixed64 { + * // must be less than or equal to 10 + * fixed64 value = 1 [(buf.validate.field).fixed64.lte = 10]; + * } + * ``` + * + * @generated from field: fixed64 lte = 3; + */ + value: bigint; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.Fixed64Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyFixed64 { + * // must be greater than 5 [fixed64.gt] + * fixed64 value = 1 [(buf.validate.field).fixed64.gt = 5]; + * + * // must be greater than 5 and less than 10 [fixed64.gt_lt] + * fixed64 other_value = 2 [(buf.validate.field).fixed64 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [fixed64.gt_lt_exclusive] + * fixed64 another_value = 3 [(buf.validate.field).fixed64 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: fixed64 gt = 4; + */ + value: bigint; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyFixed64 { + * // must be greater than or equal to 5 [fixed64.gte] + * fixed64 value = 1 [(buf.validate.field).fixed64.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [fixed64.gte_lt] + * fixed64 other_value = 2 [(buf.validate.field).fixed64 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [fixed64.gte_lt_exclusive] + * fixed64 another_value = 3 [(buf.validate.field).fixed64 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: fixed64 gte = 5; + */ + value: bigint; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MyFixed64 { + * // must be in list [1, 2, 3] + * fixed64 value = 1 [(buf.validate.field).fixed64 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated fixed64 in = 6; + */ + in: bigint[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MyFixed64 { + * // value must not be in list [1, 2, 3] + * fixed64 value = 1 [(buf.validate.field).fixed64 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated fixed64 not_in = 7; + */ + notIn: bigint[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyFixed64 { + * fixed64 value = 1 [ + * (buf.validate.field).fixed64.example = 1, + * (buf.validate.field).fixed64.example = 2 + * ]; + * } + * ``` + * + * @generated from field: repeated fixed64 example = 8; + */ + example: bigint[]; +}; + +/** + * Describes the message buf.validate.Fixed64Rules. + * Use `create(Fixed64RulesSchema)` to create a new message. + */ +export const Fixed64RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 15); + +/** + * SFixed32Rules describes the rules applied to `fixed32` values. + * + * @generated from message buf.validate.SFixed32Rules + */ +export type SFixed32Rules = Message<"buf.validate.SFixed32Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MySFixed32 { + * // value must equal 42 + * sfixed32 value = 1 [(buf.validate.field).sfixed32.const = 42]; + * } + * ``` + * + * @generated from field: optional sfixed32 const = 1; + */ + const: number; + + /** + * @generated from oneof buf.validate.SFixed32Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MySFixed32 { + * // must be less than 10 + * sfixed32 value = 1 [(buf.validate.field).sfixed32.lt = 10]; + * } + * ``` + * + * @generated from field: sfixed32 lt = 2; + */ + value: number; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MySFixed32 { + * // must be less than or equal to 10 + * sfixed32 value = 1 [(buf.validate.field).sfixed32.lte = 10]; + * } + * ``` + * + * @generated from field: sfixed32 lte = 3; + */ + value: number; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.SFixed32Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySFixed32 { + * // must be greater than 5 [sfixed32.gt] + * sfixed32 value = 1 [(buf.validate.field).sfixed32.gt = 5]; + * + * // must be greater than 5 and less than 10 [sfixed32.gt_lt] + * sfixed32 other_value = 2 [(buf.validate.field).sfixed32 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [sfixed32.gt_lt_exclusive] + * sfixed32 another_value = 3 [(buf.validate.field).sfixed32 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sfixed32 gt = 4; + */ + value: number; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySFixed32 { + * // must be greater than or equal to 5 [sfixed32.gte] + * sfixed32 value = 1 [(buf.validate.field).sfixed32.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [sfixed32.gte_lt] + * sfixed32 other_value = 2 [(buf.validate.field).sfixed32 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [sfixed32.gte_lt_exclusive] + * sfixed32 another_value = 3 [(buf.validate.field).sfixed32 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sfixed32 gte = 5; + */ + value: number; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MySFixed32 { + * // must be in list [1, 2, 3] + * sfixed32 value = 1 [(buf.validate.field).sfixed32 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sfixed32 in = 6; + */ + in: number[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MySFixed32 { + * // value must not be in list [1, 2, 3] + * sfixed32 value = 1 [(buf.validate.field).sfixed32 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sfixed32 not_in = 7; + */ + notIn: number[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MySFixed32 { + * sfixed32 value = 1 [ + * (buf.validate.field).sfixed32.example = 1, + * (buf.validate.field).sfixed32.example = 2 + * ]; + * } + * ``` + * + * @generated from field: repeated sfixed32 example = 8; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.SFixed32Rules. + * Use `create(SFixed32RulesSchema)` to create a new message. + */ +export const SFixed32RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 16); + +/** + * SFixed64Rules describes the rules applied to `fixed64` values. + * + * @generated from message buf.validate.SFixed64Rules + */ +export type SFixed64Rules = Message<"buf.validate.SFixed64Rules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MySFixed64 { + * // value must equal 42 + * sfixed64 value = 1 [(buf.validate.field).sfixed64.const = 42]; + * } + * ``` + * + * @generated from field: optional sfixed64 const = 1; + */ + const: bigint; + + /** + * @generated from oneof buf.validate.SFixed64Rules.less_than + */ + lessThan: { + /** + * `lt` requires the field value to be less than the specified value (field < + * value). If the field value is equal to or greater than the specified value, + * an error message is generated. + * + * ```proto + * message MySFixed64 { + * // must be less than 10 + * sfixed64 value = 1 [(buf.validate.field).sfixed64.lt = 10]; + * } + * ``` + * + * @generated from field: sfixed64 lt = 2; + */ + value: bigint; + case: "lt"; + } | { + /** + * `lte` requires the field value to be less than or equal to the specified + * value (field <= value). If the field value is greater than the specified + * value, an error message is generated. + * + * ```proto + * message MySFixed64 { + * // must be less than or equal to 10 + * sfixed64 value = 1 [(buf.validate.field).sfixed64.lte = 10]; + * } + * ``` + * + * @generated from field: sfixed64 lte = 3; + */ + value: bigint; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.SFixed64Rules.greater_than + */ + greaterThan: { + /** + * `gt` requires the field value to be greater than the specified value + * (exclusive). If the value of `gt` is larger than a specified `lt` or + * `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySFixed64 { + * // must be greater than 5 [sfixed64.gt] + * sfixed64 value = 1 [(buf.validate.field).sfixed64.gt = 5]; + * + * // must be greater than 5 and less than 10 [sfixed64.gt_lt] + * sfixed64 other_value = 2 [(buf.validate.field).sfixed64 = { gt: 5, lt: 10 }]; + * + * // must be greater than 10 or less than 5 [sfixed64.gt_lt_exclusive] + * sfixed64 another_value = 3 [(buf.validate.field).sfixed64 = { gt: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sfixed64 gt = 4; + */ + value: bigint; + case: "gt"; + } | { + /** + * `gte` requires the field value to be greater than or equal to the specified + * value (exclusive). If the value of `gte` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MySFixed64 { + * // must be greater than or equal to 5 [sfixed64.gte] + * sfixed64 value = 1 [(buf.validate.field).sfixed64.gte = 5]; + * + * // must be greater than or equal to 5 and less than 10 [sfixed64.gte_lt] + * sfixed64 other_value = 2 [(buf.validate.field).sfixed64 = { gte: 5, lt: 10 }]; + * + * // must be greater than or equal to 10 or less than 5 [sfixed64.gte_lt_exclusive] + * sfixed64 another_value = 3 [(buf.validate.field).sfixed64 = { gte: 10, lt: 5 }]; + * } + * ``` + * + * @generated from field: sfixed64 gte = 5; + */ + value: bigint; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` requires the field value to be equal to one of the specified values. + * If the field value isn't one of the specified values, an error message is + * generated. + * + * ```proto + * message MySFixed64 { + * // must be in list [1, 2, 3] + * sfixed64 value = 1 [(buf.validate.field).sfixed64 = { in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sfixed64 in = 6; + */ + in: bigint[]; + + /** + * `not_in` requires the field value to not be equal to any of the specified + * values. If the field value is one of the specified values, an error + * message is generated. + * + * ```proto + * message MySFixed64 { + * // value must not be in list [1, 2, 3] + * sfixed64 value = 1 [(buf.validate.field).sfixed64 = { not_in: [1, 2, 3] }]; + * } + * ``` + * + * @generated from field: repeated sfixed64 not_in = 7; + */ + notIn: bigint[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MySFixed64 { + * sfixed64 value = 1 [ + * (buf.validate.field).sfixed64.example = 1, + * (buf.validate.field).sfixed64.example = 2 + * ]; + * } + * ``` + * + * @generated from field: repeated sfixed64 example = 8; + */ + example: bigint[]; +}; + +/** + * Describes the message buf.validate.SFixed64Rules. + * Use `create(SFixed64RulesSchema)` to create a new message. + */ +export const SFixed64RulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 17); + +/** + * BoolRules describes the rules applied to `bool` values. These rules + * may also be applied to the `google.protobuf.BoolValue` Well-Known-Type. + * + * @generated from message buf.validate.BoolRules + */ +export type BoolRules = Message<"buf.validate.BoolRules"> & { + /** + * `const` requires the field value to exactly match the specified boolean value. + * If the field value doesn't match, an error message is generated. + * + * ```proto + * message MyBool { + * // value must equal true + * bool value = 1 [(buf.validate.field).bool.const = true]; + * } + * ``` + * + * @generated from field: optional bool const = 1; + */ + const: boolean; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyBool { + * bool value = 1 [ + * (buf.validate.field).bool.example = true, + * (buf.validate.field).bool.example = false + * ]; + * } + * ``` + * + * @generated from field: repeated bool example = 2; + */ + example: boolean[]; +}; + +/** + * Describes the message buf.validate.BoolRules. + * Use `create(BoolRulesSchema)` to create a new message. + */ +export const BoolRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 18); + +/** + * StringRules describes the rules applied to `string` values These + * rules may also be applied to the `google.protobuf.StringValue` Well-Known-Type. + * + * @generated from message buf.validate.StringRules + */ +export type StringRules = Message<"buf.validate.StringRules"> & { + /** + * `const` requires the field value to exactly match the specified value. If + * the field value doesn't match, an error message is generated. + * + * ```proto + * message MyString { + * // value must equal `hello` + * string value = 1 [(buf.validate.field).string.const = "hello"]; + * } + * ``` + * + * @generated from field: optional string const = 1; + */ + const: string; + + /** + * `len` dictates that the field value must have the specified + * number of characters (Unicode code points), which may differ from the number + * of bytes in the string. If the field value does not meet the specified + * length, an error message will be generated. + * + * ```proto + * message MyString { + * // value length must be 5 characters + * string value = 1 [(buf.validate.field).string.len = 5]; + * } + * ``` + * + * @generated from field: optional uint64 len = 19; + */ + len: bigint; + + /** + * `min_len` specifies that the field value must have at least the specified + * number of characters (Unicode code points), which may differ from the number + * of bytes in the string. If the field value contains fewer characters, an error + * message will be generated. + * + * ```proto + * message MyString { + * // value length must be at least 3 characters + * string value = 1 [(buf.validate.field).string.min_len = 3]; + * } + * ``` + * + * @generated from field: optional uint64 min_len = 2; + */ + minLen: bigint; + + /** + * `max_len` specifies that the field value must have no more than the specified + * number of characters (Unicode code points), which may differ from the + * number of bytes in the string. If the field value contains more characters, + * an error message will be generated. + * + * ```proto + * message MyString { + * // value length must be at most 10 characters + * string value = 1 [(buf.validate.field).string.max_len = 10]; + * } + * ``` + * + * @generated from field: optional uint64 max_len = 3; + */ + maxLen: bigint; + + /** + * `len_bytes` dictates that the field value must have the specified number of + * bytes. If the field value does not match the specified length in bytes, + * an error message will be generated. + * + * ```proto + * message MyString { + * // value length must be 6 bytes + * string value = 1 [(buf.validate.field).string.len_bytes = 6]; + * } + * ``` + * + * @generated from field: optional uint64 len_bytes = 20; + */ + lenBytes: bigint; + + /** + * `min_bytes` specifies that the field value must have at least the specified + * number of bytes. If the field value contains fewer bytes, an error message + * will be generated. + * + * ```proto + * message MyString { + * // value length must be at least 4 bytes + * string value = 1 [(buf.validate.field).string.min_bytes = 4]; + * } + * + * ``` + * + * @generated from field: optional uint64 min_bytes = 4; + */ + minBytes: bigint; + + /** + * `max_bytes` specifies that the field value must have no more than the + * specified number of bytes. If the field value contains more bytes, an + * error message will be generated. + * + * ```proto + * message MyString { + * // value length must be at most 8 bytes + * string value = 1 [(buf.validate.field).string.max_bytes = 8]; + * } + * ``` + * + * @generated from field: optional uint64 max_bytes = 5; + */ + maxBytes: bigint; + + /** + * `pattern` specifies that the field value must match the specified + * regular expression (RE2 syntax), with the expression provided without any + * delimiters. If the field value doesn't match the regular expression, an + * error message will be generated. + * + * ```proto + * message MyString { + * // value does not match regex pattern `^[a-zA-Z]//$` + * string value = 1 [(buf.validate.field).string.pattern = "^[a-zA-Z]//$"]; + * } + * ``` + * + * @generated from field: optional string pattern = 6; + */ + pattern: string; + + /** + * `prefix` specifies that the field value must have the + * specified substring at the beginning of the string. If the field value + * doesn't start with the specified prefix, an error message will be + * generated. + * + * ```proto + * message MyString { + * // value does not have prefix `pre` + * string value = 1 [(buf.validate.field).string.prefix = "pre"]; + * } + * ``` + * + * @generated from field: optional string prefix = 7; + */ + prefix: string; + + /** + * `suffix` specifies that the field value must have the + * specified substring at the end of the string. If the field value doesn't + * end with the specified suffix, an error message will be generated. + * + * ```proto + * message MyString { + * // value does not have suffix `post` + * string value = 1 [(buf.validate.field).string.suffix = "post"]; + * } + * ``` + * + * @generated from field: optional string suffix = 8; + */ + suffix: string; + + /** + * `contains` specifies that the field value must have the + * specified substring anywhere in the string. If the field value doesn't + * contain the specified substring, an error message will be generated. + * + * ```proto + * message MyString { + * // value does not contain substring `inside`. + * string value = 1 [(buf.validate.field).string.contains = "inside"]; + * } + * ``` + * + * @generated from field: optional string contains = 9; + */ + contains: string; + + /** + * `not_contains` specifies that the field value must not have the + * specified substring anywhere in the string. If the field value contains + * the specified substring, an error message will be generated. + * + * ```proto + * message MyString { + * // value contains substring `inside`. + * string value = 1 [(buf.validate.field).string.not_contains = "inside"]; + * } + * ``` + * + * @generated from field: optional string not_contains = 23; + */ + notContains: string; + + /** + * `in` specifies that the field value must be equal to one of the specified + * values. If the field value isn't one of the specified values, an error + * message will be generated. + * + * ```proto + * message MyString { + * // must be in list ["apple", "banana"] + * string value = 1 [(buf.validate.field).string = { in: ["apple", "banana"] }]; + * } + * ``` + * + * @generated from field: repeated string in = 10; + */ + in: string[]; + + /** + * `not_in` specifies that the field value cannot be equal to any + * of the specified values. If the field value is one of the specified values, + * an error message will be generated. + * ```proto + * message MyString { + * // value must not be in list ["orange", "grape"] + * string value = 1 [(buf.validate.field).string = { not_in: ["orange", "grape"] }]; + * } + * ``` + * + * @generated from field: repeated string not_in = 11; + */ + notIn: string[]; + + /** + * `WellKnown` rules provide advanced rules against common string + * patterns. + * + * @generated from oneof buf.validate.StringRules.well_known + */ + wellKnown: { + /** + * `email` specifies that the field value must be a valid email address, for + * example "foo@example.com". + * + * Conforms to the definition for a valid email address from the [HTML standard](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address). + * Note that this standard willfully deviates from [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322), + * which allows many unexpected forms of email addresses and will easily match + * a typographical error. + * + * If the field value isn't a valid email address, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid email address + * string value = 1 [(buf.validate.field).string.email = true]; + * } + * ``` + * + * @generated from field: bool email = 12; + */ + value: boolean; + case: "email"; + } | { + /** + * `hostname` specifies that the field value must be a valid hostname, for + * example "foo.example.com". + * + * A valid hostname follows the rules below: + * - The name consists of one or more labels, separated by a dot ("."). + * - Each label can be 1 to 63 alphanumeric characters. + * - A label can contain hyphens ("-"), but must not start or end with a hyphen. + * - The right-most label must not be digits only. + * - The name can have a trailing dot—for example, "foo.example.com.". + * - The name can be 253 characters at most, excluding the optional trailing dot. + * + * If the field value isn't a valid hostname, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid hostname + * string value = 1 [(buf.validate.field).string.hostname = true]; + * } + * ``` + * + * @generated from field: bool hostname = 13; + */ + value: boolean; + case: "hostname"; + } | { + /** + * `ip` specifies that the field value must be a valid IP (v4 or v6) address. + * + * IPv4 addresses are expected in the dotted decimal format—for example, "192.168.5.21". + * IPv6 addresses are expected in their text representation—for example, "::1", + * or "2001:0DB8:ABCD:0012::0". + * + * Both formats are well-defined in the internet standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). + * Zone identifiers for IPv6 addresses (for example, "fe80::a%en1") are supported. + * + * If the field value isn't a valid IP address, an error message will be + * generated. + * + * ```proto + * message MyString { + * // must be a valid IP address + * string value = 1 [(buf.validate.field).string.ip = true]; + * } + * ``` + * + * @generated from field: bool ip = 14; + */ + value: boolean; + case: "ip"; + } | { + /** + * `ipv4` specifies that the field value must be a valid IPv4 address—for + * example "192.168.5.21". If the field value isn't a valid IPv4 address, an + * error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid IPv4 address + * string value = 1 [(buf.validate.field).string.ipv4 = true]; + * } + * ``` + * + * @generated from field: bool ipv4 = 15; + */ + value: boolean; + case: "ipv4"; + } | { + /** + * `ipv6` specifies that the field value must be a valid IPv6 address—for + * example "::1", or "d7a:115c:a1e0:ab12:4843:cd96:626b:430b". If the field + * value is not a valid IPv6 address, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid IPv6 address + * string value = 1 [(buf.validate.field).string.ipv6 = true]; + * } + * ``` + * + * @generated from field: bool ipv6 = 16; + */ + value: boolean; + case: "ipv6"; + } | { + /** + * `uri` specifies that the field value must be a valid URI, for example + * "https://example.com/foo/bar?baz=quux#frag". + * + * URI is defined in the internet standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). + * Zone Identifiers in IPv6 address literals are supported ([RFC 6874](https://datatracker.ietf.org/doc/html/rfc6874)). + * + * If the field value isn't a valid URI, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid URI + * string value = 1 [(buf.validate.field).string.uri = true]; + * } + * ``` + * + * @generated from field: bool uri = 17; + */ + value: boolean; + case: "uri"; + } | { + /** + * `uri_ref` specifies that the field value must be a valid URI Reference—either + * a URI such as "https://example.com/foo/bar?baz=quux#frag", or a Relative + * Reference such as "./foo/bar?query". + * + * URI, URI Reference, and Relative Reference are defined in the internet + * standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986). Zone + * Identifiers in IPv6 address literals are supported ([RFC 6874](https://datatracker.ietf.org/doc/html/rfc6874)). + * + * If the field value isn't a valid URI Reference, an error message will be + * generated. + * + * ```proto + * message MyString { + * // must be a valid URI Reference + * string value = 1 [(buf.validate.field).string.uri_ref = true]; + * } + * ``` + * + * @generated from field: bool uri_ref = 18; + */ + value: boolean; + case: "uriRef"; + } | { + /** + * `address` specifies that the field value must be either a valid hostname + * (for example, "example.com"), or a valid IP (v4 or v6) address (for example, + * "192.168.0.1", or "::1"). If the field value isn't a valid hostname or IP, + * an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid hostname, or ip address + * string value = 1 [(buf.validate.field).string.address = true]; + * } + * ``` + * + * @generated from field: bool address = 21; + */ + value: boolean; + case: "address"; + } | { + /** + * `uuid` specifies that the field value must be a valid UUID as defined by + * [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2). If the + * field value isn't a valid UUID, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid UUID + * string value = 1 [(buf.validate.field).string.uuid = true]; + * } + * ``` + * + * @generated from field: bool uuid = 22; + */ + value: boolean; + case: "uuid"; + } | { + /** + * `tuuid` (trimmed UUID) specifies that the field value must be a valid UUID as + * defined by [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2) with all dashes + * omitted. If the field value isn't a valid UUID without dashes, an error message + * will be generated. + * + * ```proto + * message MyString { + * // must be a valid trimmed UUID + * string value = 1 [(buf.validate.field).string.tuuid = true]; + * } + * ``` + * + * @generated from field: bool tuuid = 33; + */ + value: boolean; + case: "tuuid"; + } | { + /** + * `ip_with_prefixlen` specifies that the field value must be a valid IP + * (v4 or v6) address with prefix length—for example, "192.168.5.21/16" or + * "2001:0DB8:ABCD:0012::F1/64". If the field value isn't a valid IP with + * prefix length, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid IP with prefix length + * string value = 1 [(buf.validate.field).string.ip_with_prefixlen = true]; + * } + * ``` + * + * @generated from field: bool ip_with_prefixlen = 26; + */ + value: boolean; + case: "ipWithPrefixlen"; + } | { + /** + * `ipv4_with_prefixlen` specifies that the field value must be a valid + * IPv4 address with prefix length—for example, "192.168.5.21/16". If the + * field value isn't a valid IPv4 address with prefix length, an error + * message will be generated. + * + * ```proto + * message MyString { + * // must be a valid IPv4 address with prefix length + * string value = 1 [(buf.validate.field).string.ipv4_with_prefixlen = true]; + * } + * ``` + * + * @generated from field: bool ipv4_with_prefixlen = 27; + */ + value: boolean; + case: "ipv4WithPrefixlen"; + } | { + /** + * `ipv6_with_prefixlen` specifies that the field value must be a valid + * IPv6 address with prefix length—for example, "2001:0DB8:ABCD:0012::F1/64". + * If the field value is not a valid IPv6 address with prefix length, + * an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid IPv6 address prefix length + * string value = 1 [(buf.validate.field).string.ipv6_with_prefixlen = true]; + * } + * ``` + * + * @generated from field: bool ipv6_with_prefixlen = 28; + */ + value: boolean; + case: "ipv6WithPrefixlen"; + } | { + /** + * `ip_prefix` specifies that the field value must be a valid IP (v4 or v6) + * prefix—for example, "192.168.0.0/16" or "2001:0DB8:ABCD:0012::0/64". + * + * The prefix must have all zeros for the unmasked bits. For example, + * "2001:0DB8:ABCD:0012::0/64" designates the left-most 64 bits for the + * prefix, and the remaining 64 bits must be zero. + * + * If the field value isn't a valid IP prefix, an error message will be + * generated. + * + * ```proto + * message MyString { + * // must be a valid IP prefix + * string value = 1 [(buf.validate.field).string.ip_prefix = true]; + * } + * ``` + * + * @generated from field: bool ip_prefix = 29; + */ + value: boolean; + case: "ipPrefix"; + } | { + /** + * `ipv4_prefix` specifies that the field value must be a valid IPv4 + * prefix, for example "192.168.0.0/16". + * + * The prefix must have all zeros for the unmasked bits. For example, + * "192.168.0.0/16" designates the left-most 16 bits for the prefix, + * and the remaining 16 bits must be zero. + * + * If the field value isn't a valid IPv4 prefix, an error message + * will be generated. + * + * ```proto + * message MyString { + * // must be a valid IPv4 prefix + * string value = 1 [(buf.validate.field).string.ipv4_prefix = true]; + * } + * ``` + * + * @generated from field: bool ipv4_prefix = 30; + */ + value: boolean; + case: "ipv4Prefix"; + } | { + /** + * `ipv6_prefix` specifies that the field value must be a valid IPv6 prefix—for + * example, "2001:0DB8:ABCD:0012::0/64". + * + * The prefix must have all zeros for the unmasked bits. For example, + * "2001:0DB8:ABCD:0012::0/64" designates the left-most 64 bits for the + * prefix, and the remaining 64 bits must be zero. + * + * If the field value is not a valid IPv6 prefix, an error message will be + * generated. + * + * ```proto + * message MyString { + * // must be a valid IPv6 prefix + * string value = 1 [(buf.validate.field).string.ipv6_prefix = true]; + * } + * ``` + * + * @generated from field: bool ipv6_prefix = 31; + */ + value: boolean; + case: "ipv6Prefix"; + } | { + /** + * `host_and_port` specifies that the field value must be a valid host/port + * pair—for example, "example.com:8080". + * + * The host can be one of: + * - An IPv4 address in dotted decimal format—for example, "192.168.5.21". + * - An IPv6 address enclosed in square brackets—for example, "[2001:0DB8:ABCD:0012::F1]". + * - A hostname—for example, "example.com". + * + * The port is separated by a colon. It must be non-empty, with a decimal number + * in the range of 0-65535, inclusive. + * + * @generated from field: bool host_and_port = 32; + */ + value: boolean; + case: "hostAndPort"; + } | { + /** + * `ulid` specifies that the field value must be a valid ULID (Universally Unique + * Lexicographically Sortable Identifier) as defined by the [ULID specification](https://github.com/ulid/spec). + * If the field value isn't a valid ULID, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid ULID + * string value = 1 [(buf.validate.field).string.ulid = true]; + * } + * ``` + * + * @generated from field: bool ulid = 35; + */ + value: boolean; + case: "ulid"; + } | { + /** + * `protobuf_fqn` specifies that the field value must be a valid fully-qualified + * Protobuf name as defined by the [Protobuf Language Specification](https://protobuf.com/docs/language-spec). + * + * A fully-qualified Protobuf name is a dot-separated list of Protobuf identifiers, + * where each identifier starts with a letter or underscore and is followed by zero or + * more letters, underscores, or digits. + * + * Examples: "buf.validate", "google.protobuf.Timestamp", "my_package.MyMessage". + * + * Note: historically, fully-qualified Protobuf names were represented with a leading + * dot (for example, ".buf.validate.StringRules"). Modern Protobuf does not use the + * leading dot, and most fully-qualified names are represented without it. Use + * `protobuf_dot_fqn` if a leading dot is required. + * + * If the field value isn't a valid fully-qualified Protobuf name, an error message + * will be generated. + * + * ```proto + * message MyString { + * // value must be a valid fully-qualified Protobuf name + * string value = 1 [(buf.validate.field).string.protobuf_fqn = true]; + * } + * ``` + * + * @generated from field: bool protobuf_fqn = 37; + */ + value: boolean; + case: "protobufFqn"; + } | { + /** + * `protobuf_dot_fqn` specifies that the field value must be a valid fully-qualified + * Protobuf name with a leading dot, as defined by the + * [Protobuf Language Specification](https://protobuf.com/docs/language-spec). + * + * A fully-qualified Protobuf name with a leading dot is a dot followed by a + * dot-separated list of Protobuf identifiers, where each identifier starts with a + * letter or underscore and is followed by zero or more letters, underscores, or + * digits. + * + * Examples: ".buf.validate", ".google.protobuf.Timestamp", ".my_package.MyMessage". + * + * Note: this is the historical representation of fully-qualified Protobuf names, + * where a leading dot denotes an absolute reference. Modern Protobuf does not use + * the leading dot, and most fully-qualified names are represented without it. Most + * users will want to use `protobuf_fqn` instead. + * + * If the field value isn't a valid fully-qualified Protobuf name with a leading dot, + * an error message will be generated. + * + * ```proto + * message MyString { + * // value must be a valid fully-qualified Protobuf name with a leading dot + * string value = 1 [(buf.validate.field).string.protobuf_dot_fqn = true]; + * } + * ``` + * + * @generated from field: bool protobuf_dot_fqn = 38; + */ + value: boolean; + case: "protobufDotFqn"; + } | { + /** + * `well_known_regex` specifies a common well-known pattern + * defined as a regex. If the field value doesn't match the well-known + * regex, an error message will be generated. + * + * ```proto + * message MyString { + * // must be a valid HTTP header value + * string value = 1 [(buf.validate.field).string.well_known_regex = KNOWN_REGEX_HTTP_HEADER_VALUE]; + * } + * ``` + * + * #### KnownRegex + * + * `well_known_regex` contains some well-known patterns. + * + * | Name | Number | Description | + * |-------------------------------|--------|-------------------------------------------| + * | KNOWN_REGEX_UNSPECIFIED | 0 | | + * | KNOWN_REGEX_HTTP_HEADER_NAME | 1 | HTTP header name as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2) | + * | KNOWN_REGEX_HTTP_HEADER_VALUE | 2 | HTTP header value as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4) | + * + * @generated from field: buf.validate.KnownRegex well_known_regex = 24; + */ + value: KnownRegex; + case: "wellKnownRegex"; + } | { case: undefined; value?: undefined }; + + /** + * This applies to regexes `HTTP_HEADER_NAME` and `HTTP_HEADER_VALUE` to + * enable strict header validation. By default, this is true, and HTTP header + * validations are [RFC-compliant](https://datatracker.ietf.org/doc/html/rfc7230#section-3). Setting to false will enable looser + * validations that only disallow `\r\n\0` characters, which can be used to + * bypass header matching rules. + * + * ```proto + * message MyString { + * // The field `value` must have be a valid HTTP headers, but not enforced with strict rules. + * string value = 1 [(buf.validate.field).string.strict = false]; + * } + * ``` + * + * @generated from field: optional bool strict = 25; + */ + strict: boolean; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyString { + * string value = 1 [ + * (buf.validate.field).string.example = "hello", + * (buf.validate.field).string.example = "world" + * ]; + * } + * ``` + * + * @generated from field: repeated string example = 34; + */ + example: string[]; +}; + +/** + * Describes the message buf.validate.StringRules. + * Use `create(StringRulesSchema)` to create a new message. + */ +export const StringRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 19); + +/** + * BytesRules describe the rules applied to `bytes` values. These rules + * may also be applied to the `google.protobuf.BytesValue` Well-Known-Type. + * + * @generated from message buf.validate.BytesRules + */ +export type BytesRules = Message<"buf.validate.BytesRules"> & { + /** + * `const` requires the field value to exactly match the specified bytes + * value. If the field value doesn't match, an error message is generated. + * + * ```proto + * message MyBytes { + * // must be "\x01\x02\x03\x04" + * bytes value = 1 [(buf.validate.field).bytes.const = "\x01\x02\x03\x04"]; + * } + * ``` + * + * @generated from field: optional bytes const = 1; + */ + const: Uint8Array; + + /** + * `len` requires the field value to have the specified length in bytes. + * If the field value doesn't match, an error message is generated. + * + * ```proto + * message MyBytes { + * // value length must be 4 bytes. + * optional bytes value = 1 [(buf.validate.field).bytes.len = 4]; + * } + * ``` + * + * @generated from field: optional uint64 len = 13; + */ + len: bigint; + + /** + * `min_len` requires the field value to have at least the specified minimum + * length in bytes. + * If the field value doesn't meet the requirement, an error message is generated. + * + * ```proto + * message MyBytes { + * // value length must be at least 2 bytes. + * optional bytes value = 1 [(buf.validate.field).bytes.min_len = 2]; + * } + * ``` + * + * @generated from field: optional uint64 min_len = 2; + */ + minLen: bigint; + + /** + * `max_len` requires the field value to have at most the specified maximum + * length in bytes. + * If the field value exceeds the requirement, an error message is generated. + * + * ```proto + * message MyBytes { + * // must be at most 6 bytes. + * optional bytes value = 1 [(buf.validate.field).bytes.max_len = 6]; + * } + * ``` + * + * @generated from field: optional uint64 max_len = 3; + */ + maxLen: bigint; + + /** + * `pattern` requires the field value to match the specified regular + * expression ([RE2 syntax](https://github.com/google/re2/wiki/Syntax)). + * The value of the field must be valid UTF-8 or validation will fail with a + * runtime error. + * If the field value doesn't match the pattern, an error message is generated. + * + * ```proto + * message MyBytes { + * // value must match regex pattern "^[a-zA-Z0-9]+$". + * optional bytes value = 1 [(buf.validate.field).bytes.pattern = "^[a-zA-Z0-9]+$"]; + * } + * ``` + * + * @generated from field: optional string pattern = 4; + */ + pattern: string; + + /** + * `prefix` requires the field value to have the specified bytes at the + * beginning of the string. + * If the field value doesn't meet the requirement, an error message is generated. + * + * ```proto + * message MyBytes { + * // value does not have prefix \x01\x02 + * optional bytes value = 1 [(buf.validate.field).bytes.prefix = "\x01\x02"]; + * } + * ``` + * + * @generated from field: optional bytes prefix = 5; + */ + prefix: Uint8Array; + + /** + * `suffix` requires the field value to have the specified bytes at the end + * of the string. + * If the field value doesn't meet the requirement, an error message is generated. + * + * ```proto + * message MyBytes { + * // value does not have suffix \x03\x04 + * optional bytes value = 1 [(buf.validate.field).bytes.suffix = "\x03\x04"]; + * } + * ``` + * + * @generated from field: optional bytes suffix = 6; + */ + suffix: Uint8Array; + + /** + * `contains` requires the field value to have the specified bytes anywhere in + * the string. + * If the field value doesn't meet the requirement, an error message is generated. + * + * ```proto + * message MyBytes { + * // value does not contain \x02\x03 + * optional bytes value = 1 [(buf.validate.field).bytes.contains = "\x02\x03"]; + * } + * ``` + * + * @generated from field: optional bytes contains = 7; + */ + contains: Uint8Array; + + /** + * `in` requires the field value to be equal to one of the specified + * values. If the field value doesn't match any of the specified values, an + * error message is generated. + * + * ```proto + * message MyBytes { + * // value must in ["\x01\x02", "\x02\x03", "\x03\x04"] + * optional bytes value = 1 [(buf.validate.field).bytes = { in: ["\x01\x02", "\x02\x03", "\x03\x04"] }]; + * } + * ``` + * + * @generated from field: repeated bytes in = 8; + */ + in: Uint8Array[]; + + /** + * `not_in` requires the field value to be not equal to any of the specified + * values. + * If the field value matches any of the specified values, an error message is + * generated. + * + * ```proto + * message MyBytes { + * // value must not in ["\x01\x02", "\x02\x03", "\x03\x04"] + * optional bytes value = 1 [(buf.validate.field).bytes = { not_in: ["\x01\x02", "\x02\x03", "\x03\x04"] }]; + * } + * ``` + * + * @generated from field: repeated bytes not_in = 9; + */ + notIn: Uint8Array[]; + + /** + * WellKnown rules provide advanced rules against common byte + * patterns + * + * @generated from oneof buf.validate.BytesRules.well_known + */ + wellKnown: { + /** + * `ip` ensures that the field `value` is a valid IP address (v4 or v6) in byte format. + * If the field value doesn't meet this rule, an error message is generated. + * + * ```proto + * message MyBytes { + * // must be a valid IP address + * optional bytes value = 1 [(buf.validate.field).bytes.ip = true]; + * } + * ``` + * + * @generated from field: bool ip = 10; + */ + value: boolean; + case: "ip"; + } | { + /** + * `ipv4` ensures that the field `value` is a valid IPv4 address in byte format. + * If the field value doesn't meet this rule, an error message is generated. + * + * ```proto + * message MyBytes { + * // must be a valid IPv4 address + * optional bytes value = 1 [(buf.validate.field).bytes.ipv4 = true]; + * } + * ``` + * + * @generated from field: bool ipv4 = 11; + */ + value: boolean; + case: "ipv4"; + } | { + /** + * `ipv6` ensures that the field `value` is a valid IPv6 address in byte format. + * If the field value doesn't meet this rule, an error message is generated. + * ```proto + * message MyBytes { + * // must be a valid IPv6 address + * optional bytes value = 1 [(buf.validate.field).bytes.ipv6 = true]; + * } + * ``` + * + * @generated from field: bool ipv6 = 12; + */ + value: boolean; + case: "ipv6"; + } | { + /** + * `uuid` ensures that the field value encodes 128-bit UUID data as defined + * by [RFC 4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.2). + * The field must contain exactly 16 bytes representing the UUID. If the + * field value isn't a valid UUID, an error message will be generated. + * + * ```proto + * message MyBytes { + * // must be a valid UUID + * optional bytes value = 1 [(buf.validate.field).bytes.uuid = true]; + * } + * ``` + * + * @generated from field: bool uuid = 15; + */ + value: boolean; + case: "uuid"; + } | { case: undefined; value?: undefined }; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyBytes { + * bytes value = 1 [ + * (buf.validate.field).bytes.example = "\x01\x02", + * (buf.validate.field).bytes.example = "\x02\x03" + * ]; + * } + * ``` + * + * @generated from field: repeated bytes example = 14; + */ + example: Uint8Array[]; +}; + +/** + * Describes the message buf.validate.BytesRules. + * Use `create(BytesRulesSchema)` to create a new message. + */ +export const BytesRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 20); + +/** + * EnumRules describe the rules applied to `enum` values. + * + * @generated from message buf.validate.EnumRules + */ +export type EnumRules = Message<"buf.validate.EnumRules"> & { + /** + * `const` requires the field value to exactly match the specified enum value. + * If the field value doesn't match, an error message is generated. + * + * ```proto + * enum MyEnum { + * MY_ENUM_UNSPECIFIED = 0; + * MY_ENUM_VALUE1 = 1; + * MY_ENUM_VALUE2 = 2; + * } + * + * message MyMessage { + * // The field `value` must be exactly MY_ENUM_VALUE1. + * MyEnum value = 1 [(buf.validate.field).enum.const = 1]; + * } + * ``` + * + * @generated from field: optional int32 const = 1; + */ + const: number; + + /** + * `defined_only` requires the field value to be one of the defined values for + * this enum, failing on any undefined value. + * + * ```proto + * enum MyEnum { + * MY_ENUM_UNSPECIFIED = 0; + * MY_ENUM_VALUE1 = 1; + * MY_ENUM_VALUE2 = 2; + * } + * + * message MyMessage { + * // The field `value` must be a defined value of MyEnum. + * MyEnum value = 1 [(buf.validate.field).enum.defined_only = true]; + * } + * ``` + * + * @generated from field: optional bool defined_only = 2; + */ + definedOnly: boolean; + + /** + * `in` requires the field value to be equal to one of the + * specified enum values. If the field value doesn't match any of the + * specified values, an error message is generated. + * + * ```proto + * enum MyEnum { + * MY_ENUM_UNSPECIFIED = 0; + * MY_ENUM_VALUE1 = 1; + * MY_ENUM_VALUE2 = 2; + * } + * + * message MyMessage { + * // The field `value` must be equal to one of the specified values. + * MyEnum value = 1 [(buf.validate.field).enum = { in: [1, 2]}]; + * } + * ``` + * + * @generated from field: repeated int32 in = 3; + */ + in: number[]; + + /** + * `not_in` requires the field value to be not equal to any of the + * specified enum values. If the field value matches one of the specified + * values, an error message is generated. + * + * ```proto + * enum MyEnum { + * MY_ENUM_UNSPECIFIED = 0; + * MY_ENUM_VALUE1 = 1; + * MY_ENUM_VALUE2 = 2; + * } + * + * message MyMessage { + * // The field `value` must not be equal to any of the specified values. + * MyEnum value = 1 [(buf.validate.field).enum = { not_in: [1, 2]}]; + * } + * ``` + * + * @generated from field: repeated int32 not_in = 4; + */ + notIn: number[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * enum MyEnum { + * MY_ENUM_UNSPECIFIED = 0; + * MY_ENUM_VALUE1 = 1; + * MY_ENUM_VALUE2 = 2; + * } + * + * message MyMessage { + * MyEnum value = 1 [ + * (buf.validate.field).enum.example = 1, + * (buf.validate.field).enum.example = 2 + * ]; + * } + * ``` + * + * @generated from field: repeated int32 example = 5; + */ + example: number[]; +}; + +/** + * Describes the message buf.validate.EnumRules. + * Use `create(EnumRulesSchema)` to create a new message. + */ +export const EnumRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 21); + +/** + * RepeatedRules describe the rules applied to `repeated` values. + * + * @generated from message buf.validate.RepeatedRules + */ +export type RepeatedRules = Message<"buf.validate.RepeatedRules"> & { + /** + * `min_items` requires that this field must contain at least the specified + * minimum number of items. + * + * Note that `min_items = 1` is equivalent to setting a field as `required`. + * + * ```proto + * message MyRepeated { + * // value must contain at least 2 items + * repeated string value = 1 [(buf.validate.field).repeated.min_items = 2]; + * } + * ``` + * + * @generated from field: optional uint64 min_items = 1; + */ + minItems: bigint; + + /** + * `max_items` denotes that this field must not exceed a + * certain number of items as the upper limit. If the field contains more + * items than specified, an error message will be generated, requiring the + * field to maintain no more than the specified number of items. + * + * ```proto + * message MyRepeated { + * // value must contain no more than 3 item(s) + * repeated string value = 1 [(buf.validate.field).repeated.max_items = 3]; + * } + * ``` + * + * @generated from field: optional uint64 max_items = 2; + */ + maxItems: bigint; + + /** + * `unique` indicates that all elements in this field must + * be unique. This rule is strictly applicable to scalar and enum + * types, with message types not being supported. + * + * ```proto + * message MyRepeated { + * // repeated value must contain unique items + * repeated string value = 1 [(buf.validate.field).repeated.unique = true]; + * } + * ``` + * + * @generated from field: optional bool unique = 3; + */ + unique: boolean; + + /** + * `items` details the rules to be applied to each item + * in the field. Even for repeated message fields, validation is executed + * against each item unless `ignore` is specified. + * + * ```proto + * message MyRepeated { + * // The items in the field `value` must follow the specified rules. + * repeated string value = 1 [(buf.validate.field).repeated.items = { + * string: { + * min_len: 3 + * max_len: 10 + * } + * }]; + * } + * ``` + * + * Note that the `required` rule does not apply. Repeated items + * cannot be unset. + * + * @generated from field: optional buf.validate.FieldRules items = 4; + */ + items?: FieldRules; +}; + +/** + * Describes the message buf.validate.RepeatedRules. + * Use `create(RepeatedRulesSchema)` to create a new message. + */ +export const RepeatedRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 22); + +/** + * MapRules describe the rules applied to `map` values. + * + * @generated from message buf.validate.MapRules + */ +export type MapRules = Message<"buf.validate.MapRules"> & { + /** + * Specifies the minimum number of key-value pairs allowed. If the field has + * fewer key-value pairs than specified, an error message is generated. + * + * ```proto + * message MyMap { + * // The field `value` must have at least 2 key-value pairs. + * map value = 1 [(buf.validate.field).map.min_pairs = 2]; + * } + * ``` + * + * @generated from field: optional uint64 min_pairs = 1; + */ + minPairs: bigint; + + /** + * Specifies the maximum number of key-value pairs allowed. If the field has + * more key-value pairs than specified, an error message is generated. + * + * ```proto + * message MyMap { + * // The field `value` must have at most 3 key-value pairs. + * map value = 1 [(buf.validate.field).map.max_pairs = 3]; + * } + * ``` + * + * @generated from field: optional uint64 max_pairs = 2; + */ + maxPairs: bigint; + + /** + * Specifies the rules to be applied to each key in the field. + * + * ```proto + * message MyMap { + * // The keys in the field `value` must follow the specified rules. + * map value = 1 [(buf.validate.field).map.keys = { + * string: { + * min_len: 3 + * max_len: 10 + * } + * }]; + * } + * ``` + * + * Note that the `required` rule does not apply. Map keys cannot be unset. + * + * @generated from field: optional buf.validate.FieldRules keys = 4; + */ + keys?: FieldRules; + + /** + * Specifies the rules to be applied to the value of each key in the + * field. Message values will still have their validations evaluated unless + * `ignore` is specified. + * + * ```proto + * message MyMap { + * // The values in the field `value` must follow the specified rules. + * map value = 1 [(buf.validate.field).map.values = { + * string: { + * min_len: 5 + * max_len: 20 + * } + * }]; + * } + * ``` + * Note that the `required` rule does not apply. Map values cannot be unset. + * + * @generated from field: optional buf.validate.FieldRules values = 5; + */ + values?: FieldRules; +}; + +/** + * Describes the message buf.validate.MapRules. + * Use `create(MapRulesSchema)` to create a new message. + */ +export const MapRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 23); + +/** + * AnyRules describe rules applied exclusively to the `google.protobuf.Any` well-known type. + * + * @generated from message buf.validate.AnyRules + */ +export type AnyRules = Message<"buf.validate.AnyRules"> & { + /** + * `in` requires the field's `type_url` to be equal to one of the + * specified values. If it doesn't match any of the specified values, an error + * message is generated. + * + * ```proto + * message MyAny { + * // The `value` field must have a `type_url` equal to one of the specified values. + * google.protobuf.Any value = 1 [(buf.validate.field).any = { + * in: ["type.googleapis.com/MyType1", "type.googleapis.com/MyType2"] + * }]; + * } + * ``` + * + * @generated from field: repeated string in = 2; + */ + in: string[]; + + /** + * `not_in` requires the field's type_url to be not equal to any of the specified values. If it matches any of the specified values, an error message is generated. + * + * ```proto + * message MyAny { + * // The `value` field must not have a `type_url` equal to any of the specified values. + * google.protobuf.Any value = 1 [(buf.validate.field).any = { + * not_in: ["type.googleapis.com/ForbiddenType1", "type.googleapis.com/ForbiddenType2"] + * }]; + * } + * ``` + * + * @generated from field: repeated string not_in = 3; + */ + notIn: string[]; +}; + +/** + * Describes the message buf.validate.AnyRules. + * Use `create(AnyRulesSchema)` to create a new message. + */ +export const AnyRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 24); + +/** + * DurationRules describe the rules applied exclusively to the `google.protobuf.Duration` well-known type. + * + * @generated from message buf.validate.DurationRules + */ +export type DurationRules = Message<"buf.validate.DurationRules"> & { + /** + * `const` dictates that the field must match the specified value of the `google.protobuf.Duration` type exactly. + * If the field's value deviates from the specified value, an error message + * will be generated. + * + * ```proto + * message MyDuration { + * // value must equal 5s + * google.protobuf.Duration value = 1 [(buf.validate.field).duration.const = { seconds: 5 }]; + * } + * ``` + * + * @generated from field: optional google.protobuf.Duration const = 2; + */ + const?: Duration; + + /** + * @generated from oneof buf.validate.DurationRules.less_than + */ + lessThan: { + /** + * `lt` stipulates that the field must be less than the specified value of the `google.protobuf.Duration` type, + * exclusive. If the field's value is greater than or equal to the specified + * value, an error message will be generated. + * + * ```proto + * message MyDuration { + * // must be less than 5s + * google.protobuf.Duration value = 1 [(buf.validate.field).duration.lt = { seconds: 5 }]; + * } + * ``` + * + * @generated from field: google.protobuf.Duration lt = 3; + */ + value: Duration; + case: "lt"; + } | { + /** + * `lte` indicates that the field must be less than or equal to the specified + * value of the `google.protobuf.Duration` type, inclusive. If the field's value is greater than the specified value, + * an error message will be generated. + * + * ```proto + * message MyDuration { + * // must be less than or equal to 10s + * google.protobuf.Duration value = 1 [(buf.validate.field).duration.lte = { seconds: 10 }]; + * } + * ``` + * + * @generated from field: google.protobuf.Duration lte = 4; + */ + value: Duration; + case: "lte"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.DurationRules.greater_than + */ + greaterThan: { + /** + * `gt` requires the duration field value to be greater than the specified + * value (exclusive). If the value of `gt` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyDuration { + * // duration must be greater than 5s [duration.gt] + * google.protobuf.Duration value = 1 [(buf.validate.field).duration.gt = { seconds: 5 }]; + * + * // duration must be greater than 5s and less than 10s [duration.gt_lt] + * google.protobuf.Duration another_value = 2 [(buf.validate.field).duration = { gt: { seconds: 5 }, lt: { seconds: 10 } }]; + * + * // duration must be greater than 10s or less than 5s [duration.gt_lt_exclusive] + * google.protobuf.Duration other_value = 3 [(buf.validate.field).duration = { gt: { seconds: 10 }, lt: { seconds: 5 } }]; + * } + * ``` + * + * @generated from field: google.protobuf.Duration gt = 5; + */ + value: Duration; + case: "gt"; + } | { + /** + * `gte` requires the duration field value to be greater than or equal to the + * specified value (exclusive). If the value of `gte` is larger than a + * specified `lt` or `lte`, the range is reversed, and the field value must + * be outside the specified range. If the field value doesn't meet the + * required conditions, an error message is generated. + * + * ```proto + * message MyDuration { + * // duration must be greater than or equal to 5s [duration.gte] + * google.protobuf.Duration value = 1 [(buf.validate.field).duration.gte = { seconds: 5 }]; + * + * // duration must be greater than or equal to 5s and less than 10s [duration.gte_lt] + * google.protobuf.Duration another_value = 2 [(buf.validate.field).duration = { gte: { seconds: 5 }, lt: { seconds: 10 } }]; + * + * // duration must be greater than or equal to 10s or less than 5s [duration.gte_lt_exclusive] + * google.protobuf.Duration other_value = 3 [(buf.validate.field).duration = { gte: { seconds: 10 }, lt: { seconds: 5 } }]; + * } + * ``` + * + * @generated from field: google.protobuf.Duration gte = 6; + */ + value: Duration; + case: "gte"; + } | { case: undefined; value?: undefined }; + + /** + * `in` asserts that the field must be equal to one of the specified values of the `google.protobuf.Duration` type. + * If the field's value doesn't correspond to any of the specified values, + * an error message will be generated. + * + * ```proto + * message MyDuration { + * // must be in list [1s, 2s, 3s] + * google.protobuf.Duration value = 1 [(buf.validate.field).duration = { + * in: [{ seconds: 1 }, { seconds: 2 }, { seconds: 3 }] + * }]; + * } + * ``` + * + * @generated from field: repeated google.protobuf.Duration in = 7; + */ + in: Duration[]; + + /** + * `not_in` denotes that the field must not be equal to + * any of the specified values of the `google.protobuf.Duration` type. + * If the field's value matches any of these values, an error message will be + * generated. + * + * ```proto + * message MyDuration { + * // value must not be in list [1s, 2s, 3s] + * google.protobuf.Duration value = 1 [(buf.validate.field).duration = { + * not_in: [{ seconds: 1 }, { seconds: 2 }, { seconds: 3 }] + * }]; + * } + * ``` + * + * @generated from field: repeated google.protobuf.Duration not_in = 8; + */ + notIn: Duration[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyDuration { + * google.protobuf.Duration value = 1 [ + * (buf.validate.field).duration.example = { seconds: 1 }, + * (buf.validate.field).duration.example = { seconds: 2 } + * ]; + * } + * ``` + * + * @generated from field: repeated google.protobuf.Duration example = 9; + */ + example: Duration[]; +}; + +/** + * Describes the message buf.validate.DurationRules. + * Use `create(DurationRulesSchema)` to create a new message. + */ +export const DurationRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 25); + +/** + * FieldMaskRules describe rules applied exclusively to the `google.protobuf.FieldMask` well-known type. + * + * @generated from message buf.validate.FieldMaskRules + */ +export type FieldMaskRules = Message<"buf.validate.FieldMaskRules"> & { + /** + * `const` dictates that the field must match the specified value of the `google.protobuf.FieldMask` type exactly. + * If the field's value deviates from the specified value, an error message + * will be generated. + * + * ```proto + * message MyFieldMask { + * // value must equal ["a"] + * google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask.const = { + * paths: ["a"] + * }]; + * } + * ``` + * + * @generated from field: optional google.protobuf.FieldMask const = 1; + */ + const?: FieldMask; + + /** + * `in` requires the field value to only contain paths matching specified + * values or their subpaths. + * If any of the field value's paths doesn't match the rule, + * an error message is generated. + * See: https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask + * + * ```proto + * message MyFieldMask { + * // The `value` FieldMask must only contain paths listed in `in`. + * google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask = { + * in: ["a", "b", "c.a"] + * }]; + * } + * ``` + * + * @generated from field: repeated string in = 2; + */ + in: string[]; + + /** + * `not_in` requires the field value to not contain paths matching specified + * values or their subpaths. + * If any of the field value's paths matches the rule, + * an error message is generated. + * See: https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask + * + * ```proto + * message MyFieldMask { + * // The `value` FieldMask shall not contain paths listed in `not_in`. + * google.protobuf.FieldMask value = 1 [(buf.validate.field).field_mask = { + * not_in: ["forbidden", "immutable", "c.a"] + * }]; + * } + * ``` + * + * @generated from field: repeated string not_in = 3; + */ + notIn: string[]; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyFieldMask { + * google.protobuf.FieldMask value = 1 [ + * (buf.validate.field).field_mask.example = { paths: ["a", "b"] }, + * (buf.validate.field).field_mask.example = { paths: ["c.a", "d"] } + * ]; + * } + * ``` + * + * @generated from field: repeated google.protobuf.FieldMask example = 4; + */ + example: FieldMask[]; +}; + +/** + * Describes the message buf.validate.FieldMaskRules. + * Use `create(FieldMaskRulesSchema)` to create a new message. + */ +export const FieldMaskRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 26); + +/** + * TimestampRules describe the rules applied exclusively to the `google.protobuf.Timestamp` well-known type. + * + * @generated from message buf.validate.TimestampRules + */ +export type TimestampRules = Message<"buf.validate.TimestampRules"> & { + /** + * `const` dictates that this field, of the `google.protobuf.Timestamp` type, must exactly match the specified value. If the field value doesn't correspond to the specified timestamp, an error message will be generated. + * + * ```proto + * message MyTimestamp { + * // value must equal 2023-05-03T10:00:00Z + * google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.const = {seconds: 1727998800}]; + * } + * ``` + * + * @generated from field: optional google.protobuf.Timestamp const = 2; + */ + const?: Timestamp; + + /** + * @generated from oneof buf.validate.TimestampRules.less_than + */ + lessThan: { + /** + * `lt` requires the timestamp field value to be less than the specified value (field < value). If the field value doesn't meet the required conditions, an error message is generated. + * + * ```proto + * message MyTimestamp { + * // timestamp must be less than '2023-01-01T00:00:00Z' [timestamp.lt] + * google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.lt = { seconds: 1672444800 }]; + * } + * ``` + * + * @generated from field: google.protobuf.Timestamp lt = 3; + */ + value: Timestamp; + case: "lt"; + } | { + /** + * `lte` requires the timestamp field value to be less than or equal to the specified value (field <= value). If the field value doesn't meet the required conditions, an error message is generated. + * + * ```proto + * message MyTimestamp { + * // timestamp must be less than or equal to '2023-05-14T00:00:00Z' [timestamp.lte] + * google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.lte = { seconds: 1678867200 }]; + * } + * ``` + * + * @generated from field: google.protobuf.Timestamp lte = 4; + */ + value: Timestamp; + case: "lte"; + } | { + /** + * `lt_now` specifies that this field, of the `google.protobuf.Timestamp` type, must be less than the current time. `lt_now` can only be used with the `within` rule. + * + * ```proto + * message MyTimestamp { + * // must be less than now + * google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.lt_now = true]; + * } + * ``` + * + * @generated from field: bool lt_now = 7; + */ + value: boolean; + case: "ltNow"; + } | { case: undefined; value?: undefined }; + + /** + * @generated from oneof buf.validate.TimestampRules.greater_than + */ + greaterThan: { + /** + * `gt` requires the timestamp field value to be greater than the specified + * value (exclusive). If the value of `gt` is larger than a specified `lt` + * or `lte`, the range is reversed, and the field value must be outside the + * specified range. If the field value doesn't meet the required conditions, + * an error message is generated. + * + * ```proto + * message MyTimestamp { + * // timestamp must be greater than '2023-01-01T00:00:00Z' [timestamp.gt] + * google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.gt = { seconds: 1672444800 }]; + * + * // timestamp must be greater than '2023-01-01T00:00:00Z' and less than '2023-01-02T00:00:00Z' [timestamp.gt_lt] + * google.protobuf.Timestamp another_value = 2 [(buf.validate.field).timestamp = { gt: { seconds: 1672444800 }, lt: { seconds: 1672531200 } }]; + * + * // timestamp must be greater than '2023-01-02T00:00:00Z' or less than '2023-01-01T00:00:00Z' [timestamp.gt_lt_exclusive] + * google.protobuf.Timestamp other_value = 3 [(buf.validate.field).timestamp = { gt: { seconds: 1672531200 }, lt: { seconds: 1672444800 } }]; + * } + * ``` + * + * @generated from field: google.protobuf.Timestamp gt = 5; + */ + value: Timestamp; + case: "gt"; + } | { + /** + * `gte` requires the timestamp field value to be greater than or equal to the + * specified value (exclusive). If the value of `gte` is larger than a + * specified `lt` or `lte`, the range is reversed, and the field value + * must be outside the specified range. If the field value doesn't meet + * the required conditions, an error message is generated. + * + * ```proto + * message MyTimestamp { + * // timestamp must be greater than or equal to '2023-01-01T00:00:00Z' [timestamp.gte] + * google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.gte = { seconds: 1672444800 }]; + * + * // timestamp must be greater than or equal to '2023-01-01T00:00:00Z' and less than '2023-01-02T00:00:00Z' [timestamp.gte_lt] + * google.protobuf.Timestamp another_value = 2 [(buf.validate.field).timestamp = { gte: { seconds: 1672444800 }, lt: { seconds: 1672531200 } }]; + * + * // timestamp must be greater than or equal to '2023-01-02T00:00:00Z' or less than '2023-01-01T00:00:00Z' [timestamp.gte_lt_exclusive] + * google.protobuf.Timestamp other_value = 3 [(buf.validate.field).timestamp = { gte: { seconds: 1672531200 }, lt: { seconds: 1672444800 } }]; + * } + * ``` + * + * @generated from field: google.protobuf.Timestamp gte = 6; + */ + value: Timestamp; + case: "gte"; + } | { + /** + * `gt_now` specifies that this field, of the `google.protobuf.Timestamp` type, must be greater than the current time. `gt_now` can only be used with the `within` rule. + * + * ```proto + * message MyTimestamp { + * // must be greater than now + * google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.gt_now = true]; + * } + * ``` + * + * @generated from field: bool gt_now = 8; + */ + value: boolean; + case: "gtNow"; + } | { case: undefined; value?: undefined }; + + /** + * `within` specifies that this field, of the `google.protobuf.Timestamp` type, must be within the specified duration of the current time. If the field value isn't within the duration, an error message is generated. + * + * ```proto + * message MyTimestamp { + * // must be within 1 hour of now + * google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.within = {seconds: 3600}]; + * } + * ``` + * + * @generated from field: optional google.protobuf.Duration within = 9; + */ + within?: Duration; + + /** + * `example` specifies values that the field may have. These values SHOULD + * conform to other rules. `example` values will not impact validation + * but may be used as helpful guidance on how to populate the given field. + * + * ```proto + * message MyTimestamp { + * google.protobuf.Timestamp value = 1 [ + * (buf.validate.field).timestamp.example = { seconds: 1672444800 }, + * (buf.validate.field).timestamp.example = { seconds: 1672531200 } + * ]; + * } + * ``` + * + * @generated from field: repeated google.protobuf.Timestamp example = 10; + */ + example: Timestamp[]; +}; + +/** + * Describes the message buf.validate.TimestampRules. + * Use `create(TimestampRulesSchema)` to create a new message. + */ +export const TimestampRulesSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 27); + +/** + * `Violations` is a collection of `Violation` messages. This message type is returned by + * Protovalidate when a proto message fails to meet the requirements set by the `Rule` validation rules. + * Each individual violation is represented by a `Violation` message. + * + * @generated from message buf.validate.Violations + */ +export type Violations = Message<"buf.validate.Violations"> & { + /** + * `violations` is a repeated field that contains all the `Violation` messages corresponding to the violations detected. + * + * @generated from field: repeated buf.validate.Violation violations = 1; + */ + violations: Violation[]; +}; + +/** + * Describes the message buf.validate.Violations. + * Use `create(ViolationsSchema)` to create a new message. + */ +export const ViolationsSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 28); + +/** + * `Violation` represents a single instance where a validation rule, expressed + * as a `Rule`, was not met. It provides information about the field that + * caused the violation, the specific rule that wasn't fulfilled, and a + * human-readable error message. + * + * For example, consider the following message: + * + * ```proto + * message User { + * int32 age = 1 [(buf.validate.field).cel = { + * id: "user.age", + * expression: "this < 18 ? 'User must be at least 18 years old' : ''", + * }]; + * } + * ``` + * + * It could produce the following violation: + * + * ```json + * { + * "ruleId": "user.age", + * "message": "User must be at least 18 years old", + * "field": { + * "elements": [ + * { + * "fieldNumber": 1, + * "fieldName": "age", + * "fieldType": "TYPE_INT32" + * } + * ] + * }, + * "rule": { + * "elements": [ + * { + * "fieldNumber": 23, + * "fieldName": "cel", + * "fieldType": "TYPE_MESSAGE", + * "index": "0" + * } + * ] + * } + * } + * ``` + * + * @generated from message buf.validate.Violation + */ +export type Violation = Message<"buf.validate.Violation"> & { + /** + * `field` is a machine-readable path to the field that failed validation. + * This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation. + * + * For example, consider the following message: + * + * ```proto + * message Message { + * bool a = 1 [(buf.validate.field).required = true]; + * } + * ``` + * + * It could produce the following violation: + * + * ```textproto + * violation { + * field { element { field_number: 1, field_name: "a", field_type: 8 } } + * ... + * } + * ``` + * + * @generated from field: optional buf.validate.FieldPath field = 5; + */ + field?: FieldPath; + + /** + * `rule` is a machine-readable path that points to the specific rule that failed validation. + * This will be a nested field starting from the FieldRules of the field that failed validation. + * For custom rules, this will provide the path of the rule, e.g. `cel[0]`. + * + * For example, consider the following message: + * + * ```proto + * message Message { + * bool a = 1 [(buf.validate.field).required = true]; + * bool b = 2 [(buf.validate.field).cel = { + * id: "custom_rule", + * expression: "!this ? 'b must be true': ''" + * }]; + * } + * ``` + * + * It could produce the following violations: + * + * ```textproto + * violation { + * rule { element { field_number: 25, field_name: "required", field_type: 8 } } + * ... + * } + * violation { + * rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } } + * ... + * } + * ``` + * + * @generated from field: optional buf.validate.FieldPath rule = 6; + */ + rule?: FieldPath; + + /** + * `rule_id` is the unique identifier of the `Rule` that was not fulfilled. + * This is the same `id` that was specified in the `Rule` message, allowing easy tracing of which rule was violated. + * + * @generated from field: optional string rule_id = 2; + */ + ruleId: string; + + /** + * `message` is a human-readable error message that describes the nature of the violation. + * This can be the default error message from the violated `Rule`, or it can be a custom message that gives more context about the violation. + * + * @generated from field: optional string message = 3; + */ + message: string; + + /** + * `for_key` indicates whether the violation was caused by a map key, rather than a value. + * + * @generated from field: optional bool for_key = 4; + */ + forKey: boolean; +}; + +/** + * Describes the message buf.validate.Violation. + * Use `create(ViolationSchema)` to create a new message. + */ +export const ViolationSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 29); + +/** + * `FieldPath` provides a path to a nested protobuf field. + * + * This message provides enough information to render a dotted field path even without protobuf descriptors. + * It also provides enough information to resolve a nested field through unknown wire data. + * + * @generated from message buf.validate.FieldPath + */ +export type FieldPath = Message<"buf.validate.FieldPath"> & { + /** + * `elements` contains each element of the path, starting from the root and recursing downward. + * + * @generated from field: repeated buf.validate.FieldPathElement elements = 1; + */ + elements: FieldPathElement[]; +}; + +/** + * Describes the message buf.validate.FieldPath. + * Use `create(FieldPathSchema)` to create a new message. + */ +export const FieldPathSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 30); + +/** + * `FieldPathElement` provides enough information to nest through a single protobuf field. + * + * If the selected field is a map or repeated field, the `subscript` value selects a specific element from it. + * A path that refers to a value nested under a map key or repeated field index will have a `subscript` value. + * The `field_type` field allows unambiguous resolution of a field even if descriptors are not available. + * + * @generated from message buf.validate.FieldPathElement + */ +export type FieldPathElement = Message<"buf.validate.FieldPathElement"> & { + /** + * `field_number` is the field number this path element refers to. + * + * @generated from field: optional int32 field_number = 1; + */ + fieldNumber: number; + + /** + * `field_name` contains the field name this path element refers to. + * This can be used to display a human-readable path even if the field number is unknown. + * + * @generated from field: optional string field_name = 2; + */ + fieldName: string; + + /** + * `field_type` specifies the type of this field. When using reflection, this value is not needed. + * + * This value is provided to make it possible to traverse unknown fields through wire data. + * When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes. + * + * [1]: https://protobuf.dev/programming-guides/encoding/#packed + * [2]: https://protobuf.dev/programming-guides/encoding/#groups + * + * N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and + * can be explicitly used in Protocol Buffers 2023 Edition. + * + * @generated from field: optional google.protobuf.FieldDescriptorProto.Type field_type = 3; + */ + fieldType: FieldDescriptorProto_Type; + + /** + * `key_type` specifies the map key type of this field. This value is useful when traversing + * unknown fields through wire data: specifically, it allows handling the differences between + * different integer encodings. + * + * @generated from field: optional google.protobuf.FieldDescriptorProto.Type key_type = 4; + */ + keyType: FieldDescriptorProto_Type; + + /** + * `value_type` specifies map value type of this field. This is useful if you want to display a + * value inside unknown fields through wire data. + * + * @generated from field: optional google.protobuf.FieldDescriptorProto.Type value_type = 5; + */ + valueType: FieldDescriptorProto_Type; + + /** + * `subscript` contains a repeated index or map key, if this path element nests into a repeated or map field. + * + * @generated from oneof buf.validate.FieldPathElement.subscript + */ + subscript: { + /** + * `index` specifies a 0-based index into a repeated field. + * + * @generated from field: uint64 index = 6; + */ + value: bigint; + case: "index"; + } | { + /** + * `bool_key` specifies a map key of type bool. + * + * @generated from field: bool bool_key = 7; + */ + value: boolean; + case: "boolKey"; + } | { + /** + * `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64. + * + * @generated from field: int64 int_key = 8; + */ + value: bigint; + case: "intKey"; + } | { + /** + * `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64. + * + * @generated from field: uint64 uint_key = 9; + */ + value: bigint; + case: "uintKey"; + } | { + /** + * `string_key` specifies a map key of type string. + * + * @generated from field: string string_key = 10; + */ + value: string; + case: "stringKey"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message buf.validate.FieldPathElement. + * Use `create(FieldPathElementSchema)` to create a new message. + */ +export const FieldPathElementSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_buf_validate_validate, 31); + +/** + * Specifies how `FieldRules.ignore` behaves, depending on the field's value, and + * whether the field tracks presence. + * + * @generated from enum buf.validate.Ignore + */ +export enum Ignore { + /** + * Ignore rules if the field tracks presence and is unset. This is the default + * behavior. + * + * In proto3, only message fields, members of a Protobuf `oneof`, and fields + * with the `optional` label track presence. Consequently, the following fields + * are always validated, whether a value is set or not: + * + * ```proto + * syntax="proto3"; + * + * message RulesApply { + * string email = 1 [ + * (buf.validate.field).string.email = true + * ]; + * int32 age = 2 [ + * (buf.validate.field).int32.gt = 0 + * ]; + * repeated string labels = 3 [ + * (buf.validate.field).repeated.min_items = 1 + * ]; + * } + * ``` + * + * In contrast, the following fields track presence, and are only validated if + * a value is set: + * + * ```proto + * syntax="proto3"; + * + * message RulesApplyIfSet { + * optional string email = 1 [ + * (buf.validate.field).string.email = true + * ]; + * oneof ref { + * string reference = 2 [ + * (buf.validate.field).string.uuid = true + * ]; + * string name = 3 [ + * (buf.validate.field).string.min_len = 4 + * ]; + * } + * SomeMessage msg = 4 [ + * (buf.validate.field).cel = {/* ... *\/} + * ]; + * } + * ``` + * + * To ensure that such a field is set, add the `required` rule. + * + * To learn which fields track presence, see the + * [Field Presence cheat sheet](https://protobuf.dev/programming-guides/field_presence/#cheat). + * + * @generated from enum value: IGNORE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * Ignore rules if the field is unset, or set to the zero value. + * + * The zero value depends on the field type: + * - For strings, the zero value is the empty string. + * - For bytes, the zero value is empty bytes. + * - For bool, the zero value is false. + * - For numeric types, the zero value is zero. + * - For enums, the zero value is the first defined enum value. + * - For repeated fields, the zero is an empty list. + * - For map fields, the zero is an empty map. + * - For message fields, absence of the message (typically a null-value) is considered zero value. + * + * For fields that track presence (e.g. adding the `optional` label in proto3), + * this a no-op and behavior is the same as the default `IGNORE_UNSPECIFIED`. + * + * @generated from enum value: IGNORE_IF_ZERO_VALUE = 1; + */ + IF_ZERO_VALUE = 1, + + /** + * Always ignore rules, including the `required` rule. + * + * This is useful for ignoring the rules of a referenced message, or to + * temporarily ignore rules during development. + * + * ```proto + * message MyMessage { + * // The field's rules will always be ignored, including any validations + * // on value's fields. + * MyOtherMessage value = 1 [ + * (buf.validate.field).ignore = IGNORE_ALWAYS + * ]; + * } + * ``` + * + * @generated from enum value: IGNORE_ALWAYS = 3; + */ + ALWAYS = 3, +} + +/** + * Describes the enum buf.validate.Ignore. + */ +export const IgnoreSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_buf_validate_validate, 0); + +/** + * KnownRegex contains some well-known patterns. + * + * @generated from enum buf.validate.KnownRegex + */ +export enum KnownRegex { + /** + * @generated from enum value: KNOWN_REGEX_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * HTTP header name as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2). + * + * @generated from enum value: KNOWN_REGEX_HTTP_HEADER_NAME = 1; + */ + HTTP_HEADER_NAME = 1, + + /** + * HTTP header value as defined by [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.4). + * + * @generated from enum value: KNOWN_REGEX_HTTP_HEADER_VALUE = 2; + */ + HTTP_HEADER_VALUE = 2, +} + +/** + * Describes the enum buf.validate.KnownRegex. + */ +export const KnownRegexSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_buf_validate_validate, 1); + +/** + * Rules specify the validations to be performed on this message. By default, + * no validation is performed against a message. + * + * @generated from extension: optional buf.validate.MessageRules message = 1159; + */ +export const message: GenExtension = /*@__PURE__*/ + extDesc(file_buf_validate_validate, 0); + +/** + * Rules specify the validations to be performed on this oneof. By default, + * no validation is performed against a oneof. + * + * @generated from extension: optional buf.validate.OneofRules oneof = 1159; + */ +export const oneof: GenExtension = /*@__PURE__*/ + extDesc(file_buf_validate_validate, 1); + +/** + * Rules specify the validations to be performed on this field. By default, + * no validation is performed against a field. + * + * @generated from extension: optional buf.validate.FieldRules field = 1159; + */ +export const field: GenExtension = /*@__PURE__*/ + extDesc(file_buf_validate_validate, 2); + +/** + * Specifies predefined rules. When extending a standard rule message, + * this adds additional CEL expressions that apply when the extension is used. + * + * ```proto + * extend buf.validate.Int32Rules { + * bool is_zero = 1001 [(buf.validate.predefined).cel = { + * id: "int32.is_zero", + * message: "must be zero", + * expression: "!rule || this == 0", + * }]; + * } + * + * message Foo { + * int32 reserved = 1 [(buf.validate.field).int32.(is_zero) = true]; + * } + * ``` + * + * @generated from extension: optional buf.validate.PredefinedRules predefined = 1160; + */ +export const predefined: GenExtension = /*@__PURE__*/ + extDesc(file_buf_validate_validate, 3); + diff --git a/libraries/authority-client/typescript/src/gen/google/api/annotations_pb.ts b/libraries/authority-client/typescript/src/gen/google/api/annotations_pb.ts new file mode 100644 index 00000000..2e9f31d0 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/google/api/annotations_pb.ts @@ -0,0 +1,39 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file google/api/annotations.proto (package google.api, syntax proto3) +/* eslint-disable */ + +import type { GenExtension, GenFile } from "@bufbuild/protobuf/codegenv2"; +import { extDesc, fileDesc } from "@bufbuild/protobuf/codegenv2"; +import type { HttpRule } from "./http_pb.js"; +import { file_google_api_http } from "./http_pb.js"; +import type { MethodOptions } from "@bufbuild/protobuf/wkt"; +import { file_google_protobuf_descriptor } from "@bufbuild/protobuf/wkt"; + +/** + * Describes the file google/api/annotations.proto. + */ +export const file_google_api_annotations: GenFile = /*@__PURE__*/ + fileDesc("Chxnb29nbGUvYXBpL2Fubm90YXRpb25zLnByb3RvEgpnb29nbGUuYXBpOksKBGh0dHASHi5nb29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxiwyrwiIAEoCzIULmdvb2dsZS5hcGkuSHR0cFJ1bGVSBGh0dHBCbgoOY29tLmdvb2dsZS5hcGlCEEFubm90YXRpb25zUHJvdG9QAVpBZ29vZ2xlLmdvbGFuZy5vcmcvZ2VucHJvdG8vZ29vZ2xlYXBpcy9hcGkvYW5ub3RhdGlvbnM7YW5ub3RhdGlvbnOiAgRHQVBJYgZwcm90bzM", [file_google_api_http, file_google_protobuf_descriptor]); + +/** + * See `HttpRule`. + * + * @generated from extension: google.api.HttpRule http = 72295728; + */ +export const http: GenExtension = /*@__PURE__*/ + extDesc(file_google_api_annotations, 0); + diff --git a/libraries/authority-client/typescript/src/gen/google/api/http_pb.ts b/libraries/authority-client/typescript/src/gen/google/api/http_pb.ts new file mode 100644 index 00000000..2a6664e0 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/google/api/http_pb.ts @@ -0,0 +1,474 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file google/api/http.proto (package google.api, syntax proto3) +/* eslint-disable */ + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file google/api/http.proto. + */ +export const file_google_api_http: GenFile = /*@__PURE__*/ + fileDesc("ChVnb29nbGUvYXBpL2h0dHAucHJvdG8SCmdvb2dsZS5hcGkiVAoESHR0cBIjCgVydWxlcxgBIAMoCzIULmdvb2dsZS5hcGkuSHR0cFJ1bGUSJwofZnVsbHlfZGVjb2RlX3Jlc2VydmVkX2V4cGFuc2lvbhgCIAEoCCKBAgoISHR0cFJ1bGUSEAoIc2VsZWN0b3IYASABKAkSDQoDZ2V0GAIgASgJSAASDQoDcHV0GAMgASgJSAASDgoEcG9zdBgEIAEoCUgAEhAKBmRlbGV0ZRgFIAEoCUgAEg8KBXBhdGNoGAYgASgJSAASLwoGY3VzdG9tGAggASgLMh0uZ29vZ2xlLmFwaS5DdXN0b21IdHRwUGF0dGVybkgAEgwKBGJvZHkYByABKAkSFQoNcmVzcG9uc2VfYm9keRgMIAEoCRIxChNhZGRpdGlvbmFsX2JpbmRpbmdzGAsgAygLMhQuZ29vZ2xlLmFwaS5IdHRwUnVsZUIJCgdwYXR0ZXJuIi8KEUN1c3RvbUh0dHBQYXR0ZXJuEgwKBGtpbmQYASABKAkSDAoEcGF0aBgCIAEoCUJnCg5jb20uZ29vZ2xlLmFwaUIJSHR0cFByb3RvUAFaQWdvb2dsZS5nb2xhbmcub3JnL2dlbnByb3RvL2dvb2dsZWFwaXMvYXBpL2Fubm90YXRpb25zO2Fubm90YXRpb25zogIER0FQSWIGcHJvdG8z"); + +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + * + * @generated from message google.api.Http + */ +export type Http = Message<"google.api.Http"> & { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + * + * @generated from field: repeated google.api.HttpRule rules = 1; + */ + rules: HttpRule[]; + + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + * + * @generated from field: bool fully_decode_reserved_expansion = 2; + */ + fullyDecodeReservedExpansion: boolean; +}; + +/** + * Describes the message google.api.Http. + * Use `create(HttpSchema)` to create a new message. + */ +export const HttpSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_google_api_http, 0); + +/** + * gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * - HTTP: `GET /v1/messages/123456` + * - gRPC: `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * - HTTP: `GET /v1/messages/123456?revision=2&sub.subfield=foo` + * - gRPC: `GetMessage(message_id: "123456" revision: 2 sub: + * SubMessage(subfield: "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }` + * - gRPC: `UpdateMessage(message_id: "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }` + * - gRPC: `UpdateMessage(message_id: "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * - HTTP: `GET /v1/messages/123456` + * - gRPC: `GetMessage(message_id: "123456")` + * + * - HTTP: `GET /v1/users/me/messages/123456` + * - gRPC: `GetMessage(user_id: "me" message_id: "123456")` + * + * Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They + * are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL + * query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP + * request body, all + * fields are passed via URL path and URL query parameters. + * + * Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * The following example selects a gRPC method and applies an `HttpRule` to it: + * + * http: + * rules: + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + * + * @generated from message google.api.HttpRule + */ +export type HttpRule = Message<"google.api.HttpRule"> & { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax + * details. + * + * @generated from field: string selector = 1; + */ + selector: string; + + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + * + * @generated from oneof google.api.HttpRule.pattern + */ + pattern: { + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + * + * @generated from field: string get = 2; + */ + value: string; + case: "get"; + } | { + /** + * Maps to HTTP PUT. Used for replacing a resource. + * + * @generated from field: string put = 3; + */ + value: string; + case: "put"; + } | { + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + * + * @generated from field: string post = 4; + */ + value: string; + case: "post"; + } | { + /** + * Maps to HTTP DELETE. Used for deleting a resource. + * + * @generated from field: string delete = 5; + */ + value: string; + case: "delete"; + } | { + /** + * Maps to HTTP PATCH. Used for updating a resource. + * + * @generated from field: string patch = 6; + */ + value: string; + case: "patch"; + } | { + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + * + * @generated from field: google.api.CustomHttpPattern custom = 8; + */ + value: CustomHttpPattern; + case: "custom"; + } | { case: undefined; value?: undefined }; + + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + * + * @generated from field: string body = 7; + */ + body: string; + + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + * + * @generated from field: string response_body = 12; + */ + responseBody: string; + + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + * + * @generated from field: repeated google.api.HttpRule additional_bindings = 11; + */ + additionalBindings: HttpRule[]; +}; + +/** + * Describes the message google.api.HttpRule. + * Use `create(HttpRuleSchema)` to create a new message. + */ +export const HttpRuleSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_google_api_http, 1); + +/** + * A custom pattern is used for defining custom HTTP verb. + * + * @generated from message google.api.CustomHttpPattern + */ +export type CustomHttpPattern = Message<"google.api.CustomHttpPattern"> & { + /** + * The name of this custom HTTP verb. + * + * @generated from field: string kind = 1; + */ + kind: string; + + /** + * The path matched by this custom verb. + * + * @generated from field: string path = 2; + */ + path: string; +}; + +/** + * Describes the message google.api.CustomHttpPattern. + * Use `create(CustomHttpPatternSchema)` to create a new message. + */ +export const CustomHttpPatternSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_google_api_http, 2); + diff --git a/libraries/authority-client/typescript/src/gen/host/artifact/v1/artifact_pb.ts b/libraries/authority-client/typescript/src/gen/host/artifact/v1/artifact_pb.ts new file mode 100644 index 00000000..01f61d85 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/host/artifact/v1/artifact_pb.ts @@ -0,0 +1,276 @@ +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file host/artifact/v1/artifact.proto (package host.artifact.v1, syntax proto3) +/* eslint-disable */ + +// The artifact interface: a person's consent to an exact authored artifact a +// module runs (an agent's configuration, an intent version), for one +// installation, under one policy. A policy is a resource kind: approving +// requires its `activate` action at the module, running requires its `run`. +// Consent is given in person and read back at every run; it is never a +// credential to execute or read anything. + +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file host/artifact/v1/artifact.proto. + */ +export const file_host_artifact_v1_artifact: GenFile = /*@__PURE__*/ + fileDesc("Ch9ob3N0L2FydGlmYWN0L3YxL2FydGlmYWN0LnByb3RvEhBob3N0LmFydGlmYWN0LnYxIjYKCENvbnRyYWN0EgwKBGtpbmQYASABKAkSDAoEbmFtZRgCIAEoCRIOCgZkaWdlc3QYAyABKAkihQEKCElkZW50aXR5Eg4KBnNjaGVtYRgBIAEoCRIOCgZzb3VyY2UYAiABKAkSDwoHc3ViamVjdBgDIAEoDBItCgljb250cmFjdHMYBCADKAsyGi5ob3N0LmFydGlmYWN0LnYxLkNvbnRyYWN0EhkKEWV4cGVjdGVkX3JldmlzaW9uGAUgASgDIpgBCg9BcnRpZmFjdFJlcXVlc3QSFAoMcGFyZW50X3Rva2VuGAEgASgJEhgKEGFjdG9yX2NyZWRlbnRpYWwYAiABKAkSFwoPaW5zdGFsbGF0aW9uX2lkGAMgASgJEg4KBnBvbGljeRgEIAEoCRIsCghpZGVudGl0eRgFIAEoCzIaLmhvc3QuYXJ0aWZhY3QudjEuSWRlbnRpdHkifQoNUmV2b2tlUmVxdWVzdBIUCgxwYXJlbnRfdG9rZW4YASABKAkSGAoQYWN0b3JfY3JlZGVudGlhbBgCIAEoCRIXCg9pbnN0YWxsYXRpb25faWQYAyABKAkSDgoGcG9saWN5GAQgASgJEhMKC2FwcHJvdmFsX2lkGAUgASgJIk0KCEFwcHJvdmFsEhYKDnF1YWxpZmllZF9uYW1lGAEgASgJEg4KBmRpZ2VzdBgCIAEoCRIZChFleHBlY3RlZF9yZXZpc2lvbhgDIAEoAzLuAQoPQXJ0aWZhY3RTZXJ2aWNlEkgKB0FwcHJvdmUSIS5ob3N0LmFydGlmYWN0LnYxLkFydGlmYWN0UmVxdWVzdBoaLmhvc3QuYXJ0aWZhY3QudjEuQXBwcm92YWwSSgoJQXV0aG9yaXplEiEuaG9zdC5hcnRpZmFjdC52MS5BcnRpZmFjdFJlcXVlc3QaGi5ob3N0LmFydGlmYWN0LnYxLkFwcHJvdmFsEkUKBlJldm9rZRIfLmhvc3QuYXJ0aWZhY3QudjEuUmV2b2tlUmVxdWVzdBoaLmhvc3QuYXJ0aWZhY3QudjEuQXBwcm92YWxCLVorZ2F0ZXdheS9wa2cvZ2VuL2hvc3QvYXJ0aWZhY3QvdjE7YXJ0aWZhY3R2MWIGcHJvdG8z"); + +/** + * Contract is one contract the artifact is compiled against. + * + * @generated from message host.artifact.v1.Contract + */ +export type Contract = Message<"host.artifact.v1.Contract"> & { + /** + * @generated from field: string kind = 1; + */ + kind: string; + + /** + * @generated from field: string name = 2; + */ + name: string; + + /** + * @generated from field: string digest = 3; + */ + digest: string; +}; + +/** + * Describes the message host.artifact.v1.Contract. + * Use `create(ContractSchema)` to create a new message. + */ +export const ContractSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_artifact_v1_artifact, 0); + +/** + * Identity is the artifact's complete canonical identity, as the module's + * compiler exports it: references and digests, never authored content. + * + * @generated from message host.artifact.v1.Identity + */ +export type Identity = Message<"host.artifact.v1.Identity"> & { + /** + * The schema the subject is written in, which owns its canonical bytes. + * + * @generated from field: string schema = 1; + */ + schema: string; + + /** + * The source the artifact belongs to. + * + * @generated from field: string source = 2; + */ + source: string; + + /** + * The canonical subject. + * + * @generated from field: bytes subject = 3; + */ + subject: Uint8Array; + + /** + * The contracts it is compiled against. + * + * @generated from field: repeated host.artifact.v1.Contract contracts = 4; + */ + contracts: Contract[]; + + /** + * The revision the module expects the approval at. + * + * @generated from field: int64 expected_revision = 5; + */ + expectedRevision: bigint; +}; + +/** + * Describes the message host.artifact.v1.Identity. + * Use `create(IdentitySchema)` to create a new message. + */ +export const IdentitySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_artifact_v1_artifact, 1); + +/** + * ArtifactRequest asks about one identity, for one installation, under one policy. + * + * @generated from message host.artifact.v1.ArtifactRequest + */ +export type ArtifactRequest = Message<"host.artifact.v1.ArtifactRequest"> & { + /** + * The Work Context the module was presented, addressed to it: whose consent + * this is, and what they hold there. + * + * @generated from field: string parent_token = 1; + */ + parentToken: string; + + /** + * The module asking, by its workload credential. + * + * @generated from field: string actor_credential = 2; + */ + actorCredential: string; + + /** + * The installation the artifact runs in. + * + * @generated from field: string installation_id = 3; + */ + installationId: string; + + /** + * The policy: a resource kind at the module. + * + * @generated from field: string policy = 4; + */ + policy: string; + + /** + * The artifact. + * + * @generated from field: host.artifact.v1.Identity identity = 5; + */ + identity?: Identity; +}; + +/** + * Describes the message host.artifact.v1.ArtifactRequest. + * Use `create(ArtifactRequestSchema)` to create a new message. + */ +export const ArtifactRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_artifact_v1_artifact, 2); + +/** + * RevokeRequest withdraws one approval. + * + * @generated from message host.artifact.v1.RevokeRequest + */ +export type RevokeRequest = Message<"host.artifact.v1.RevokeRequest"> & { + /** + * @generated from field: string parent_token = 1; + */ + parentToken: string; + + /** + * @generated from field: string actor_credential = 2; + */ + actorCredential: string; + + /** + * @generated from field: string installation_id = 3; + */ + installationId: string; + + /** + * The policy the approval was given under. + * + * @generated from field: string policy = 4; + */ + policy: string; + + /** + * The approval, by its id. + * + * @generated from field: string approval_id = 5; + */ + approvalId: string; +}; + +/** + * Describes the message host.artifact.v1.RevokeRequest. + * Use `create(RevokeRequestSchema)` to create a new message. + */ +export const RevokeRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_artifact_v1_artifact, 3); + +/** + * Approval is the host's exact consent reference. + * + * @generated from message host.artifact.v1.Approval + */ +export type Approval = Message<"host.artifact.v1.Approval"> & { + /** + * host/approved-artifacts/. + * + * @generated from field: string qualified_name = 1; + */ + qualifiedName: string; + + /** + * sha256: of the identity approved. + * + * @generated from field: string digest = 2; + */ + digest: string; + + /** + * The revision the approval was given at. + * + * @generated from field: int64 expected_revision = 3; + */ + expectedRevision: bigint; +}; + +/** + * Describes the message host.artifact.v1.Approval. + * Use `create(ApprovalSchema)` to create a new message. + */ +export const ApprovalSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_artifact_v1_artifact, 4); + +/** + * ArtifactService is implemented by the host and by the local authority. + * + * @generated from service host.artifact.v1.ArtifactService + */ +export const ArtifactService: GenService<{ + /** + * Approve records the person's consent to the identity for the installation + * under the policy. The person is present: the parent is theirs, addressed + * to the asking module, with no module acting between, and holds the policy + * kind's activate action there. An identity already approved answers the + * same approval; one whose approval was revoked is refused. Consent is + * durable: the host keeps it in its store, so it outlives the process that + * recorded it and answers every run until it is revoked. + * + * @generated from rpc host.artifact.v1.ArtifactService.Approve + */ + approve: { + methodKind: "unary"; + input: typeof ArtifactRequestSchema; + output: typeof ApprovalSchema; + }, + /** + * Authorize answers the standing approval of the identity, for a run: the + * parent may be delegated and holds the policy kind's run action. It never + * creates consent. + * + * @generated from rpc host.artifact.v1.ArtifactService.Authorize + */ + authorize: { + methodKind: "unary"; + input: typeof ArtifactRequestSchema; + output: typeof ApprovalSchema; + }, + /** + * Revoke withdraws an approval, permanently, for a person present holding + * the policy kind's activate action. + * + * @generated from rpc host.artifact.v1.ArtifactService.Revoke + */ + revoke: { + methodKind: "unary"; + input: typeof RevokeRequestSchema; + output: typeof ApprovalSchema; + }, +}> = /*@__PURE__*/ + serviceDesc(file_host_artifact_v1_artifact, 0); + diff --git a/libraries/authority-client/typescript/src/gen/host/authority/v1/authority_pb.ts b/libraries/authority-client/typescript/src/gen/host/authority/v1/authority_pb.ts new file mode 100644 index 00000000..ec333289 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/host/authority/v1/authority_pb.ts @@ -0,0 +1,792 @@ +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file host/authority/v1/authority.proto (package host.authority.v1, syntax proto3) +/* eslint-disable */ + +// The authority interface: what a module or solution calls on its host to be +// issued a Work Context, to have one checked, and to learn the keys it was +// signed with, and to ask which resources of a kind it covers. Every former spelling (start task, start +// installation task, exchange audience, start child, renew, the module broker's +// mints) is Issue with a different `as`. + +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2"; +import { file_google_api_annotations } from "../../../google/api/annotations_pb.js"; +import type { WorkContextV1, WorkScopeV1 } from "./work_context_pb.js"; +import { file_host_authority_v1_work_context } from "./work_context_pb.js"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file host/authority/v1/authority.proto. + */ +export const file_host_authority_v1_authority: GenFile = /*@__PURE__*/ + fileDesc("CiFob3N0L2F1dGhvcml0eS92MS9hdXRob3JpdHkucHJvdG8SEWhvc3QuYXV0aG9yaXR5LnYxIuYDCgxJc3N1ZVJlcXVlc3QSMgoGcGVyc29uGAEgASgLMiAuaG9zdC5hdXRob3JpdHkudjEuUGVyc29uU2Vzc2lvbkgAEjkKCHdvcmtsb2FkGAIgASgLMiUuaG9zdC5hdXRob3JpdHkudjEuV29ya2xvYWRDcmVkZW50aWFsSAASOgoMaW5zdGFsbGF0aW9uGAMgASgLMiIuaG9zdC5hdXRob3JpdHkudjEuSW5zdGFsbGF0aW9uUmVmSAASFgoMcGFyZW50X3Rva2VuGAQgASgJSAASNgoKZGVsZWdhdGlvbhgLIAEoCzIgLmhvc3QuYXV0aG9yaXR5LnYxLkRlbGVnYXRpb25SZWZIABIQCghhdWRpZW5jZRgFIAEoCRIuCgZzY29wZXMYBiADKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMRITCgt0dGxfc2Vjb25kcxgHIAEoAxIcChRvcGVyYXRpb25fYmluZGluZ19pZBgIIAEoCRIXCg9vcmdhbml6YXRpb25faWQYCSABKAkSNAoFYWN0b3IYCiABKAsyJS5ob3N0LmF1dGhvcml0eS52MS5Xb3JrbG9hZENyZWRlbnRpYWwSEQoJb3BlcmF0aW9uGAwgASgJQgQKAmFzIiYKDURlbGVnYXRpb25SZWYSFQoNZGVsZWdhdGlvbl9pZBgBIAEoCSJiCg9EZWxlZ2F0ZVJlcXVlc3QSDgoGbW9kdWxlGAEgASgJEi4KBnNjb3BlcxgCIAMoCzIeLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtTY29wZVYxEg8KB3B1cnBvc2UYAyABKAkirgEKCkRlbGVnYXRpb24SFQoNZGVsZWdhdGlvbl9pZBgBIAEoCRIXCg9vcmdhbml6YXRpb25faWQYAiABKAkSDwoHZ3JhbnRvchgDIAEoCRIOCgZtb2R1bGUYBCABKAkSLgoGc2NvcGVzGAUgAygLMh4uaG9zdC5hdXRob3JpdHkudjEuV29ya1Njb3BlVjESDwoHcHVycG9zZRgGIAEoCRIOCgZhY3RpdmUYByABKAgiYwoUR2V0RGVsZWdhdGlvblJlcXVlc3QSFQoNZGVsZWdhdGlvbl9pZBgBIAEoCRI0CgVhY3RvchgCIAEoCzIlLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtsb2FkQ3JlZGVudGlhbCIwChdSZXZva2VEZWxlZ2F0aW9uUmVxdWVzdBIVCg1kZWxlZ2F0aW9uX2lkGAEgASgJIk0KGFJldm9rZURlbGVnYXRpb25SZXNwb25zZRIxCgpkZWxlZ2F0aW9uGAEgASgLMh0uaG9zdC5hdXRob3JpdHkudjEuRGVsZWdhdGlvbiIhCg1QZXJzb25TZXNzaW9uSgQIARACUgpzZXNzaW9uX2lkIigKEldvcmtsb2FkQ3JlZGVudGlhbBISCgpjcmVkZW50aWFsGAEgASgJIioKD0luc3RhbGxhdGlvblJlZhIXCg9pbnN0YWxsYXRpb25faWQYASABKAkiagoNSXNzdWVSZXNwb25zZRINCgV0b2tlbhgBIAEoCRIXCg9leHBpcmVzX2F0X3VuaXgYAiABKAMSMQoHY29udGV4dBgDIAEoCzIgLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtDb250ZXh0VjEiUQoMQ2hlY2tSZXF1ZXN0Eg0KBXRva2VuGAEgASgJEhAKCGF1ZGllbmNlGAIgASgJEg4KBm1ldGhvZBgDIAEoCRIQCghhZHZpc29yeRgEIAEoCCJzCg1DaGVja1Jlc3BvbnNlEjEKB2NvbnRleHQYASABKAsyIC5ob3N0LmF1dGhvcml0eS52MS5Xb3JrQ29udGV4dFYxEh4KFmF1dGhvcml6YXRpb25fcmV2aXNpb24YAiABKAQSDwoHcmVmdXNhbBgDIAEoCSINCgtLZXlzUmVxdWVzdCJKCgxLZXlzUmVzcG9uc2USDgoGaXNzdWVyGAEgASgJEioKBGtleXMYAiADKAsyHC5ob3N0LmF1dGhvcml0eS52MS5QdWJsaWNLZXkiQgoJUHVibGljS2V5Eg4KBmtleV9pZBgBIAEoCRIRCglhbGdvcml0aG0YAiABKAkSEgoKcHVibGljX2tleRgDIAEoDCJeChRMaXN0UmVzb3VyY2VzUmVxdWVzdBINCgV0b2tlbhgBIAEoCRIQCghhdWRpZW5jZRgCIAEoCRIVCg1yZXNvdXJjZV9raW5kGAMgASgJEg4KBmFjdGlvbhgEIAEoCSJJChVMaXN0UmVzb3VyY2VzUmVzcG9uc2USMAoGZ3JhbnRzGAEgAygLMiAuaG9zdC5hdXRob3JpdHkudjEuUmVzb3VyY2VHcmFudCJaCg1SZXNvdXJjZUdyYW50Eg0KA2FsbBgBIAEoCEgAEgwKAmlkGAIgASgJSAASEAoGcHJlZml4GAMgASgJSAASEQoHcGF0dGVybhgEIAEoCUgAQgcKBW1hdGNoMqwFChBBdXRob3JpdHlTZXJ2aWNlEmoKBUlzc3VlEh8uaG9zdC5hdXRob3JpdHkudjEuSXNzdWVSZXF1ZXN0GiAuaG9zdC5hdXRob3JpdHkudjEuSXNzdWVSZXNwb25zZSIegtPkkwIYOgEqIhMvdjEvYXV0aG9yaXR5Omlzc3VlEmoKBUNoZWNrEh8uaG9zdC5hdXRob3JpdHkudjEuQ2hlY2tSZXF1ZXN0GiAuaG9zdC5hdXRob3JpdHkudjEuQ2hlY2tSZXNwb25zZSIegtPkkwIYOgEqIhMvdjEvYXV0aG9yaXR5OmNoZWNrEkcKBEtleXMSHi5ob3N0LmF1dGhvcml0eS52MS5LZXlzUmVxdWVzdBofLmhvc3QuYXV0aG9yaXR5LnYxLktleXNSZXNwb25zZRJiCg1MaXN0UmVzb3VyY2VzEicuaG9zdC5hdXRob3JpdHkudjEuTGlzdFJlc291cmNlc1JlcXVlc3QaKC5ob3N0LmF1dGhvcml0eS52MS5MaXN0UmVzb3VyY2VzUmVzcG9uc2USTQoIRGVsZWdhdGUSIi5ob3N0LmF1dGhvcml0eS52MS5EZWxlZ2F0ZVJlcXVlc3QaHS5ob3N0LmF1dGhvcml0eS52MS5EZWxlZ2F0aW9uEmsKEFJldm9rZURlbGVnYXRpb24SKi5ob3N0LmF1dGhvcml0eS52MS5SZXZva2VEZWxlZ2F0aW9uUmVxdWVzdBorLmhvc3QuYXV0aG9yaXR5LnYxLlJldm9rZURlbGVnYXRpb25SZXNwb25zZRJXCg1HZXREZWxlZ2F0aW9uEicuaG9zdC5hdXRob3JpdHkudjEuR2V0RGVsZWdhdGlvblJlcXVlc3QaHS5ob3N0LmF1dGhvcml0eS52MS5EZWxlZ2F0aW9uQi9aLWdhdGV3YXkvcGtnL2dlbi9ob3N0L2F1dGhvcml0eS92MTthdXRob3JpdHl2MWIGcHJvdG8z", [file_google_api_annotations, file_host_authority_v1_work_context]); + +/** + * IssueRequest names on whose behalf the capability is issued. + * + * @generated from message host.authority.v1.IssueRequest + */ +export type IssueRequest = Message<"host.authority.v1.IssueRequest"> & { + /** + * Who the capability is for; exactly one. + * + * @generated from oneof host.authority.v1.IssueRequest.as + */ + as: { + /** + * The signed-in person making this call, identified by the bearer the call + * carries; the host opened that session at sign-in. + * + * @generated from field: host.authority.v1.PersonSession person = 1; + */ + value: PersonSession; + case: "person"; + } | { + /** + * A module's own workload, proving which module it is. + * + * @generated from field: host.authority.v1.WorkloadCredential workload = 2; + */ + value: WorkloadCredential; + case: "workload"; + } | { + /** + * An installation acting for itself, with the scope the organisation consented to. + * actor must authenticate a workload of that installation's solution. + * + * @generated from field: host.authority.v1.InstallationRef installation = 3; + */ + value: InstallationRef; + case: "installation"; + } | { + /** + * One more hop from an existing capability: a child, an exchange or a renewal. + * + * @generated from field: string parent_token = 4; + */ + value: string; + case: "parentToken"; + } | { + /** + * A delegation a person granted the module acting (actor): the capability + * is owned by that person and carries the delegation on the module's hop. + * No live capability is presented: the authority re-checks the delegation + * and what its grantor holds now, so a revoked delegation or a lost role + * stops the next issue, and renewing is issuing again. + * + * @generated from field: host.authority.v1.DelegationRef delegation = 11; + */ + value: DelegationRef; + case: "delegation"; + } | { case: undefined; value?: undefined }; + + /** + * The module principal that may consume the capability. + * + * @generated from field: string audience = 5; + */ + audience: string; + + /** + * The scopes asked for; empty means everything the owner holds at the audience. + * + * @generated from field: repeated host.authority.v1.WorkScopeV1 scopes = 6; + */ + scopes: WorkScopeV1[]; + + /** + * Requested lifetime in seconds; clamped to the issuer's ceiling. + * + * @generated from field: int64 ttl_seconds = 7; + */ + ttlSeconds: bigint; + + /** + * The declared binding this capability exercises, when the owner is a workload + * or a child acts through one. + * + * @generated from field: string operation_binding_id = 8; + */ + operationBindingId: string; + + /** + * The organisation the work runs in. A workload may leave this empty when + * exactly one organisation has an active installation of its module. + * Otherwise it must name the organisation of the work item; + * absent or ambiguous installation authority is refused with a reason. + * + * @generated from field: string organization_id = 9; + */ + organizationId: string; + + /** + * The acting workload credential; required with parent_token, delegation, + * and installation. For installation it must name the installed solution. + * + * @generated from field: host.authority.v1.WorkloadCredential actor = 10; + */ + actor?: WorkloadCredential; + + /** + * Which of the binding's operations the capability is for: "invoke" (the + * default for a person, a child or a delegation), "headless" (the default for + * a workload) or "lookup": the binding's lookup scopes alone, to read a + * receipt without the authority to repeat the effect. + * + * @generated from field: string operation = 12; + */ + operation: string; +}; + +/** + * Describes the message host.authority.v1.IssueRequest. + * Use `create(IssueRequestSchema)` to create a new message. + */ +export const IssueRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 0); + +/** + * DelegationRef names one delegation. + * + * @generated from message host.authority.v1.DelegationRef + */ +export type DelegationRef = Message<"host.authority.v1.DelegationRef"> & { + /** + * The delegation's id, as Delegate answered it. + * + * @generated from field: string delegation_id = 1; + */ + delegationId: string; +}; + +/** + * Describes the message host.authority.v1.DelegationRef. + * Use `create(DelegationRefSchema)` to create a new message. + */ +export const DelegationRefSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 1); + +/** + * DelegateRequest is a signed-in person granting a module the right to act for + * them beyond any session: on scopes they hold, through the module's bindings. + * + * @generated from message host.authority.v1.DelegateRequest + */ +export type DelegateRequest = Message<"host.authority.v1.DelegateRequest"> & { + /** + * The module granted, by principal. + * + * @generated from field: string module = 1; + */ + module: string; + + /** + * What the module may do for the person; within what the person holds. + * + * @generated from field: repeated host.authority.v1.WorkScopeV1 scopes = 2; + */ + scopes: WorkScopeV1[]; + + /** + * Why, as the person was told (a connected source, a scheduled job). + * + * @generated from field: string purpose = 3; + */ + purpose: string; +}; + +/** + * Describes the message host.authority.v1.DelegateRequest. + * Use `create(DelegateRequestSchema)` to create a new message. + */ +export const DelegateRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 2); + +/** + * Delegation is one grant from a person to a module. + * + * @generated from message host.authority.v1.Delegation + */ +export type Delegation = Message<"host.authority.v1.Delegation"> & { + /** + * @generated from field: string delegation_id = 1; + */ + delegationId: string; + + /** + * @generated from field: string organization_id = 2; + */ + organizationId: string; + + /** + * The person who granted it, and whom every capability issued from it is for. + * + * @generated from field: string grantor = 3; + */ + grantor: string; + + /** + * The module granted. + * + * @generated from field: string module = 4; + */ + module: string; + + /** + * @generated from field: repeated host.authority.v1.WorkScopeV1 scopes = 5; + */ + scopes: WorkScopeV1[]; + + /** + * @generated from field: string purpose = 6; + */ + purpose: string; + + /** + * False once revoked; a revoked delegation issues nothing. + * + * @generated from field: bool active = 7; + */ + active: boolean; +}; + +/** + * Describes the message host.authority.v1.Delegation. + * Use `create(DelegationSchema)` to create a new message. + */ +export const DelegationSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 3); + +/** + * GetDelegationRequest names the delegation read; anyone but its module or its + * grantor is told it does not exist. + * + * @generated from message host.authority.v1.GetDelegationRequest + */ +export type GetDelegationRequest = Message<"host.authority.v1.GetDelegationRequest"> & { + /** + * @generated from field: string delegation_id = 1; + */ + delegationId: string; + + /** + * The module asking, proving which module it is; absent when the grantor asks. + * + * @generated from field: host.authority.v1.WorkloadCredential actor = 2; + */ + actor?: WorkloadCredential; +}; + +/** + * Describes the message host.authority.v1.GetDelegationRequest. + * Use `create(GetDelegationRequestSchema)` to create a new message. + */ +export const GetDelegationRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 4); + +/** + * RevokeDelegationRequest ends a delegation; only its grantor may. + * + * @generated from message host.authority.v1.RevokeDelegationRequest + */ +export type RevokeDelegationRequest = Message<"host.authority.v1.RevokeDelegationRequest"> & { + /** + * @generated from field: string delegation_id = 1; + */ + delegationId: string; +}; + +/** + * Describes the message host.authority.v1.RevokeDelegationRequest. + * Use `create(RevokeDelegationRequestSchema)` to create a new message. + */ +export const RevokeDelegationRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 5); + +/** + * RevokeDelegationResponse is the delegation as it now stands. + * + * @generated from message host.authority.v1.RevokeDelegationResponse + */ +export type RevokeDelegationResponse = Message<"host.authority.v1.RevokeDelegationResponse"> & { + /** + * @generated from field: host.authority.v1.Delegation delegation = 1; + */ + delegation?: Delegation; +}; + +/** + * Describes the message host.authority.v1.RevokeDelegationResponse. + * Use `create(RevokeDelegationResponseSchema)` to create a new message. + */ +export const RevokeDelegationResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 6); + +/** + * PersonSession names the caller's own session. It carries no field: the person + * is whoever the bearer on the call authenticates as, so a caller cannot ask for + * another person's authority by naming a session. + * + * @generated from message host.authority.v1.PersonSession + */ +export type PersonSession = Message<"host.authority.v1.PersonSession"> & { +}; + +/** + * Describes the message host.authority.v1.PersonSession. + * Use `create(PersonSessionSchema)` to create a new message. + */ +export const PersonSessionSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 7); + +/** + * WorkloadCredential proves which module a running process is: the native + * launcher credential core's workloadidentity defines, signed by the one launcher + * the host was handed an anchor for. + * + * @generated from message host.authority.v1.WorkloadCredential + */ +export type WorkloadCredential = Message<"host.authority.v1.WorkloadCredential"> & { + /** + * The launcher-signed credential, as core's native issuer writes it. + * + * @generated from field: string credential = 1; + */ + credential: string; +}; + +/** + * Describes the message host.authority.v1.WorkloadCredential. + * Use `create(WorkloadCredentialSchema)` to create a new message. + */ +export const WorkloadCredentialSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 8); + +/** + * InstallationRef names an installation acting for itself. + * + * @generated from message host.authority.v1.InstallationRef + */ +export type InstallationRef = Message<"host.authority.v1.InstallationRef"> & { + /** + * The installation id. + * + * @generated from field: string installation_id = 1; + */ + installationId: string; +}; + +/** + * Describes the message host.authority.v1.InstallationRef. + * Use `create(InstallationRefSchema)` to create a new message. + */ +export const InstallationRefSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 9); + +/** + * IssueResponse carries the signed capability and its decoded form. + * + * @generated from message host.authority.v1.IssueResponse + */ +export type IssueResponse = Message<"host.authority.v1.IssueResponse"> & { + /** + * The signed capability, as a caller presents it. + * + * @generated from field: string token = 1; + */ + token: string; + + /** + * When the capability expires. + * + * @generated from field: int64 expires_at_unix = 2; + */ + expiresAtUnix: bigint; + + /** + * The decoded capability, for the holder to read its own claims. + * + * @generated from field: host.authority.v1.WorkContextV1 context = 3; + */ + context?: WorkContextV1; +}; + +/** + * Describes the message host.authority.v1.IssueResponse. + * Use `create(IssueResponseSchema)` to create a new message. + */ +export const IssueResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 10); + +/** + * CheckRequest presents a capability for verification. + * + * @generated from message host.authority.v1.CheckRequest + */ +export type CheckRequest = Message<"host.authority.v1.CheckRequest"> & { + /** + * The capability presented. + * + * @generated from field: string token = 1; + */ + token: string; + + /** + * The audience the caller is; a capability addressed elsewhere is refused. + * + * @generated from field: string audience = 2; + */ + audience: string; + + /** + * The method the capability is presented to: "/package.Service/Method" for a + * gRPC call, " " for an HTTP request (GET /v1/model/profiles), + * matched against the routes the module declares. When set, the check also + * applies what the audience module's delivery declares for that method, and + * refuses by name a call that does not hold it, a method that declares + * nothing, and a method the module does not serve. + * + * @generated from field: string method = 3; + */ + method: string; + + /** + * Advisory asks for the policy decision without its refusal: the capability + * is still verified and refused when it is not sound, but what the method + * declares is only reported, in CheckResponse.refusal, and the verified + * capability is answered. A hop in a composition that runs permissive + * (hop/ENFORCEMENT=warn) asks this way and logs the refusal it did not make. + * Hosts may refuse advisory outside local development runs. + * + * @generated from field: bool advisory = 4; + */ + advisory: boolean; +}; + +/** + * Describes the message host.authority.v1.CheckRequest. + * Use `create(CheckRequestSchema)` to create a new message. + */ +export const CheckRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 11); + +/** + * CheckResponse is the verified capability. + * + * @generated from message host.authority.v1.CheckResponse + */ +export type CheckResponse = Message<"host.authority.v1.CheckResponse"> & { + /** + * The verified capability. + * + * @generated from field: host.authority.v1.WorkContextV1 context = 1; + */ + context?: WorkContextV1; + + /** + * The owner's authorization revision as of this check. + * + * @generated from field: uint64 authorization_revision = 2; + */ + authorizationRevision: bigint; + + /** + * Refusal is what the method's policy would have refused, verbatim, when the + * check was advisory and the policy did not hold; empty when it held. + * + * @generated from field: string refusal = 3; + */ + refusal: string; +}; + +/** + * Describes the message host.authority.v1.CheckResponse. + * Use `create(CheckResponseSchema)` to create a new message. + */ +export const CheckResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 12); + +/** + * KeysRequest asks for the verification keys. + * + * @generated from message host.authority.v1.KeysRequest + */ +export type KeysRequest = Message<"host.authority.v1.KeysRequest"> & { +}; + +/** + * Describes the message host.authority.v1.KeysRequest. + * Use `create(KeysRequestSchema)` to create a new message. + */ +export const KeysRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 13); + +/** + * KeysResponse is the issuer and its keys. + * + * @generated from message host.authority.v1.KeysResponse + */ +export type KeysResponse = Message<"host.authority.v1.KeysResponse"> & { + /** + * The issuer every capability names. + * + * @generated from field: string issuer = 1; + */ + issuer: string; + + /** + * The public keys by key id. + * + * @generated from field: repeated host.authority.v1.PublicKey keys = 2; + */ + keys: PublicKey[]; +}; + +/** + * Describes the message host.authority.v1.KeysResponse. + * Use `create(KeysResponseSchema)` to create a new message. + */ +export const KeysResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 14); + +/** + * PublicKey is one verification key. + * + * @generated from message host.authority.v1.PublicKey + */ +export type PublicKey = Message<"host.authority.v1.PublicKey"> & { + /** + * The key id a capability names. + * + * @generated from field: string key_id = 1; + */ + keyId: string; + + /** + * The signature algorithm; Ed25519. + * + * @generated from field: string algorithm = 2; + */ + algorithm: string; + + /** + * The raw public key bytes. + * + * @generated from field: bytes public_key = 3; + */ + publicKey: Uint8Array; +}; + +/** + * Describes the message host.authority.v1.PublicKey. + * Use `create(PublicKeySchema)` to create a new message. + */ +export const PublicKeySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 15); + +/** + * ListResourcesRequest asks about one kind and one action. + * + * @generated from message host.authority.v1.ListResourcesRequest + */ +export type ListResourcesRequest = Message<"host.authority.v1.ListResourcesRequest"> & { + /** + * The capability presented. + * + * @generated from field: string token = 1; + */ + token: string; + + /** + * The audience the caller is; a capability addressed elsewhere is refused. + * + * @generated from field: string audience = 2; + */ + audience: string; + + /** + * The resource kind, as the audience module serves it. + * + * @generated from field: string resource_kind = 3; + */ + resourceKind: string; + + /** + * The action, in the kind's own vocabulary. + * + * @generated from field: string action = 4; + */ + action: string; +}; + +/** + * Describes the message host.authority.v1.ListResourcesRequest. + * Use `create(ListResourcesRequestSchema)` to create a new message. + */ +export const ListResourcesRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 16); + +/** + * ListResourcesResponse is every grant the capability holds on the kind for the + * action. A resource is covered when any grant matches its id; no grant means + * none. A capability that does not hold the action at all is refused instead. + * + * @generated from message host.authority.v1.ListResourcesResponse + */ +export type ListResourcesResponse = Message<"host.authority.v1.ListResourcesResponse"> & { + /** + * @generated from field: repeated host.authority.v1.ResourceGrant grants = 1; + */ + grants: ResourceGrant[]; +}; + +/** + * Describes the message host.authority.v1.ListResourcesResponse. + * Use `create(ListResourcesResponseSchema)` to create a new message. + */ +export const ListResourcesResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 17); + +/** + * ResourceGrant is one way of naming covered resources. Exactly one is set. + * + * @generated from message host.authority.v1.ResourceGrant + */ +export type ResourceGrant = Message<"host.authority.v1.ResourceGrant"> & { + /** + * @generated from oneof host.authority.v1.ResourceGrant.match + */ + match: { + /** + * Every resource of the kind. + * + * @generated from field: bool all = 1; + */ + value: boolean; + case: "all"; + } | { + /** + * Exactly this resource id. + * + * @generated from field: string id = 2; + */ + value: string; + case: "id"; + } | { + /** + * Every resource whose id starts with this. + * + * @generated from field: string prefix = 3; + */ + value: string; + case: "prefix"; + } | { + /** + * Every resource whose whole id matches this RE2 expression, at most 256 + * bytes; it is matched against the entire id, as if anchored. + * + * @generated from field: string pattern = 4; + */ + value: string; + case: "pattern"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message host.authority.v1.ResourceGrant. + * Use `create(ResourceGrantSchema)` to create a new message. + */ +export const ResourceGrantSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_authority, 18); + +/** + * AuthorityService is implemented by the host (accounts) and by the local authority. + * + * @generated from service host.authority.v1.AuthorityService + */ +export const AuthorityService: GenService<{ + /** + * Issue signs a Work Context for one owner shape, one audience and the scopes + * asked for, bounded by what the owner holds and what the audience declared. + * Served over REST too (POST /v1/authority:issue), for a module with no + * generated client of its own, as a Python service: the same request and + * answer, in JSON. + * + * @generated from rpc host.authority.v1.AuthorityService.Issue + */ + issue: { + methodKind: "unary"; + input: typeof IssueRequestSchema; + output: typeof IssueResponseSchema; + }, + /** + * Check verifies a presented Work Context for the audience the caller is, + * re-checking the authorization revision and the seal live. + * + * @generated from rpc host.authority.v1.AuthorityService.Check + */ + check: { + methodKind: "unary"; + input: typeof CheckRequestSchema; + output: typeof CheckResponseSchema; + }, + /** + * Keys returns the issuer and the public keys a verifier pins. + * + * @generated from rpc host.authority.v1.AuthorityService.Keys + */ + keys: { + methodKind: "unary"; + input: typeof KeysRequestSchema; + output: typeof KeysResponseSchema; + }, + /** + * ListResources answers which resources of one kind a checked capability may + * act on with one action, decided by the authority at the time of the call + * rather than carried in the capability. A module maps the answer onto its + * own resources; the authority knows them only by id. + * + * @generated from rpc host.authority.v1.AuthorityService.ListResources + */ + listResources: { + methodKind: "unary"; + input: typeof ListResourcesRequestSchema; + output: typeof ListResourcesResponseSchema; + }, + /** + * Delegate records a signed-in person's grant to a module (the caller's + * bearer is the person); Issue with a delegation acts on it. + * + * @generated from rpc host.authority.v1.AuthorityService.Delegate + */ + delegate: { + methodKind: "unary"; + input: typeof DelegateRequestSchema; + output: typeof DelegationSchema; + }, + /** + * RevokeDelegation ends a delegation; the next Issue from it is refused. + * + * @generated from rpc host.authority.v1.AuthorityService.RevokeDelegation + */ + revokeDelegation: { + methodKind: "unary"; + input: typeof RevokeDelegationRequestSchema; + output: typeof RevokeDelegationResponseSchema; + }, + /** + * GetDelegation reads one delegation for the module it is granted to (by its + * workload credential) or for its grantor (by the caller's bearer): whether it + * still stands. Work that outlives the capability that started it asks this + * between issues, so a revoke stops it even when it calls no other module. + * + * @generated from rpc host.authority.v1.AuthorityService.GetDelegation + */ + getDelegation: { + methodKind: "unary"; + input: typeof GetDelegationRequestSchema; + output: typeof DelegationSchema; + }, +}> = /*@__PURE__*/ + serviceDesc(file_host_authority_v1_authority, 0); + diff --git a/libraries/authority-client/typescript/src/gen/host/authority/v1/work_context_pb.ts b/libraries/authority-client/typescript/src/gen/host/authority/v1/work_context_pb.ts new file mode 100644 index 00000000..85fa0b03 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/host/authority/v1/work_context_pb.ts @@ -0,0 +1,651 @@ +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file host/authority/v1/work_context.proto (package host.authority.v1, syntax proto3) +/* eslint-disable */ + +// Moved from codefly-dev/core proto/codefly/base/v0/work_context.proto on 2026-10-21. +// Every message, field name and field number is unchanged, so the deterministic +// bytes a verifier reads are identical; only the package and the Go import path +// differ. The conformance fixtures prove it. A change in meaning is a V2 message +// beside the V1, never a field reinterpreted. + +import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2"; +import { file_buf_validate_validate } from "../../../buf/validate/validate_pb.js"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file host/authority/v1/work_context.proto. + */ +export const file_host_authority_v1_work_context: GenFile = /*@__PURE__*/ + fileDesc("CiRob3N0L2F1dGhvcml0eS92MS93b3JrX2NvbnRleHQucHJvdG8SEWhvc3QuYXV0aG9yaXR5LnYxItAJCg1Xb3JrQ29udGV4dFYxEisKA3R5cBgBIAEoCUIeukgbchkKF2NvZGVmbHkud29yay1jb250ZXh0L3YxEiEKCWFsZ29yaXRobRgCIAEoCUIOukgLcgkKB0VkMjU1MTkSGgoGa2V5X2lkGAMgASgJQgq6SAdyBRABGIABEhoKBmlzc3VlchgEIAEoCUIKukgHcgUQARiABBIcCghhdWRpZW5jZRgFIAEoCUIKukgHcgUQARiABBIXCg9ub3RfYmVmb3JlX3VuaXgYBiABKAMSFgoOaXNzdWVkX2F0X3VuaXgYByABKAMSFwoPZXhwaXJlc19hdF91bml4GAggASgDEhkKBW5vbmNlGAkgASgJQgq6SAdyBRABGIAEEh4KFmF1dGhvcml6YXRpb25fcmV2aXNpb24YCiABKAQSNAoNcmVwbGF5X3BvbGljeRgLIAEoCUIdukgachhSCmlkZW1wb3RlbnRSCnNpbmdsZS11c2USHQoJdGVuYW50X2lkGAwgASgJQgq6SAdyBRABGIAEEiYKEm93bmVyX3ByaW5jaXBhbF9pZBgNIAEoCUIKukgHcgUQARiABBIbCgd0YXNrX2lkGA4gASgJQgq6SAdyBRABGIAEEh4KCnNlc3Npb25faWQYDyABKAlCCrpIB3IFEAEYgAQSKgoRcGFyZW50X3Nlc3Npb25faWQYECABKAlCCrpIB3IFEAEYgARIAIgBARI4ChBhdXRob3JpdHlfc2NvcGVzGBEgAygLMh4uaG9zdC5hdXRob3JpdHkudjEuV29ya1Njb3BlVjESMwoLYWN0b3JfY2hhaW4YEiADKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrQWN0b3JWMRIcChRhdHRyaWJ1dGlvbl90ZWFtX2lkcxgTIAMoCRIlCgx3b3Jrc3BhY2VfaWQYFCABKAlCCrpIB3IFEAEYgARIAYgBARIjCgpwcm9qZWN0X2lkGBUgASgJQgq6SAdyBRABGIAESAKIAQESLQoUb3duZXJfcHJpbmNpcGFsX2tpbmQYFiABKAlCCrpIB3IFEAEYgAFIA4gBARInCg5vd25lcl9hZ2VudF9pZBgXIAEoCUIKukgHcgUQARiABEgEiAEBEigKD29yZ2FuaXphdGlvbl9pZBgZIAEoCUIKukgHcgUQARiABEgFiAEBEjkKCWdyYW50X2hvcBgYIAEoCzIhLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtHcmFudEhvcFYxSAaIAQESMwoEc2VhbBgaIAEoCzIdLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtTZWFsVjFCBrpIA8gBARJJChFvcGVyYXRpb25fYmluZGluZxgbIAEoCzIpLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtPcGVyYXRpb25CaW5kaW5nVjFIB4gBAUIUChJfcGFyZW50X3Nlc3Npb25faWRCDwoNX3dvcmtzcGFjZV9pZEINCgtfcHJvamVjdF9pZEIXChVfb3duZXJfcHJpbmNpcGFsX2tpbmRCEQoPX293bmVyX2FnZW50X2lkQhIKEF9vcmdhbml6YXRpb25faWRCDAoKX2dyYW50X2hvcEIUChJfb3BlcmF0aW9uX2JpbmRpbmciqAEKCldvcmtTZWFsVjESIAoPcHJpbmNpcGFsX2Vwb2NoGAEgASgEQge6SAQyAigBEiMKD2luc3RhbGxhdGlvbl9pZBgCIAEoCUIKukgHcgUQARiABBImChVpbnN0YWxsYXRpb25fcmV2aXNpb24YAyABKARCB7pIBDICKAFKBAgEEAVKBAgFEAZSEWJ1aWxkX2luY2FybmF0aW9uUgxpbWFnZV9kaWdlc3QicQoWV29ya09wZXJhdGlvbkJpbmRpbmdWMRIeCgpiaW5kaW5nX2lkGAEgASgJQgq6SAdyBRABGIAEEhkKCHJldmlzaW9uGAIgASgEQge6SAQyAigBEhwKC2luY2FybmF0aW9uGAMgASgEQge6SAQyAigBIlcKC1dvcmtTY29wZVYxEiEKDXJlc291cmNlX2tpbmQYASABKAlCCrpIB3IFEAEYgAESDwoHYWN0aW9ucxgCIAMoCRIUCgxyZXNvdXJjZV9pZHMYAyADKAki7gIKC1dvcmtBY3RvclYxEiAKDHByaW5jaXBhbF9pZBgBIAEoCUIKukgHcgUQARiABBIiCg5wcmluY2lwYWxfa2luZBgCIAEoCUIKukgHcgUQARiAARIhCg1kZWxlZ2F0aW9uX2lkGAMgASgJQgq6SAdyBRABGIAEEjYKDmdyYW50ZWRfc2NvcGVzGAQgAygLMh4uaG9zdC5hdXRob3JpdHkudjEuV29ya1Njb3BlVjESIQoIYWdlbnRfaWQYBSABKAlCCrpIB3IFEAEYgARIAIgBARIoCg9vcmdhbml6YXRpb25faWQYBiABKAlCCrpIB3IFEAEYgARIAYgBARIjCg9wcmluY2lwYWxfZXBvY2gYByABKARCCrpIB8gBATICKAFCCwoJX2FnZW50X2lkQhIKEF9vcmdhbml6YXRpb25faWRKBAgIEAlKBAgJEApSDGltYWdlX2RpZ2VzdFIRYnVpbGRfaW5jYXJuYXRpb24i8AEKDldvcmtHcmFudEhvcFYxEhwKCGdyYW50X2lkGAEgASgJQgq6SAdyBRABGIAEEkAKCWFwcHJvdmVycxgCIAMoCzIhLmhvc3QuYXV0aG9yaXR5LnYxLldvcmtBcHByb3ZlclYxQgq6SAeSAQQIARBAEj0KDWdyYW50ZWRfc2NvcGUYAyABKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMUIGukgDyAEBEhsKB3N1YmplY3QYBCABKAlCCrpIB3IFEAEYgAQSIgoOcmVxdWVzdF9kaWdlc3QYBSABKAlCCrpIB3IFEAEYgAQiVgoOV29ya0FwcHJvdmVyVjESIAoMcHJpbmNpcGFsX2lkGAEgASgJQgq6SAdyBRABGIAEEiIKDnByaW5jaXBhbF9raW5kGAIgASgJQgq6SAdyBRABGIABItQBChJBcHByb3ZhbFJlcXVpcmVkVjESHgoKcmVxdWVzdF9pZBgBIAEoCUIKukgHcgUQARiABBI/Cg9yZXF1ZXN0ZWRfc2NvcGUYAiABKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMUIGukgDyAEBEhsKB3N1YmplY3QYAyABKAlCCrpIB3IFEAEYgAQSIgoOcmVxdWVzdF9kaWdlc3QYBCABKAlCCrpIB3IFEAEYgAQSHAoIYXVkaWVuY2UYBSABKAlCCrpIB3IFEAEYgARCL1otZ2F0ZXdheS9wa2cvZ2VuL2hvc3QvYXV0aG9yaXR5L3YxO2F1dGhvcml0eXYxYgZwcm90bzM", [file_buf_validate_validate]); + +/** + * WorkContextV1 is the product-neutral identity and authority capability for + * one Task/Session hop. The signed wire representation is owned by Codefly + * SDKs; applications must never serialize this message into a bearer token or + * construct the transport header themselves. + * + * Task identity is the tuple (tenant_id, owner_principal_id, task_id). + * Starting a child agent keeps that tuple and exchanges the parent capability + * for a new child session capability. It never mutates an existing capability. + * + * @generated from message host.authority.v1.WorkContextV1 + */ +export type WorkContextV1 = Message<"host.authority.v1.WorkContextV1"> & { + /** + * typ is fixed to "codefly.work-context/v1". + * + * @generated from field: string typ = 1; + */ + typ: string; + + /** + * algorithm is fixed to "Ed25519". + * + * @generated from field: string algorithm = 2; + */ + algorithm: string; + + /** + * key_id selects one public verification key during rotation. + * + * @generated from field: string key_id = 3; + */ + keyId: string; + + /** + * issuer is the authority that verified identity and minted this context. + * + * @generated from field: string issuer = 4; + */ + issuer: string; + + /** + * audience is the exact service or trust boundary allowed to consume it. + * + * @generated from field: string audience = 5; + */ + audience: string; + + /** + * not_before_unix is the earliest instant a verifier may accept this + * capability. + * + * @generated from field: int64 not_before_unix = 6; + */ + notBeforeUnix: bigint; + + /** + * issued_at_unix is when the issuer minted it. + * + * @generated from field: int64 issued_at_unix = 7; + */ + issuedAtUnix: bigint; + + /** + * expires_at_unix is the instant it stops being accepted. Exchanging a + * parent capability for a child one never extends it. + * + * @generated from field: int64 expires_at_unix = 8; + */ + expiresAtUnix: bigint; + + /** + * nonce identifies the capability. Replay behavior is separately explicit. + * + * @generated from field: string nonce = 9; + */ + nonce: string; + + /** + * authorization_revision is the issuer's current membership/policy revision. + * + * @generated from field: uint64 authorization_revision = 10; + */ + authorizationRevision: bigint; + + /** + * replay_policy is "idempotent" or "single-use". A verifier still needs a + * durable replay store to enforce single-use consumption. + * + * @generated from field: string replay_policy = 11; + */ + replayPolicy: string; + + /** + * tenant_id is the first element of the task identity tuple and is carried + * unchanged across every hop. + * + * @generated from field: string tenant_id = 12; + */ + tenantId: string; + + /** + * owner_principal_id is the principal on whose authority the task runs. It + * is the delegating owner, not necessarily the current actor. + * + * @generated from field: string owner_principal_id = 13; + */ + ownerPrincipalId: string; + + /** + * task_id completes the task identity tuple and survives child agents. + * + * @generated from field: string task_id = 14; + */ + taskId: string; + + /** + * session_id identifies this hop. Starting a child agent mints a new one + * rather than mutating this capability. + * + * @generated from field: string session_id = 15; + */ + sessionId: string; + + /** + * parent_session_id is the session this one was exchanged from; absent on + * the first session of a task. + * + * @generated from field: optional string parent_session_id = 16; + */ + parentSessionId?: string; + + /** + * authority_scopes are the maximum scopes the owner delegated into this + * Work Context. Each actor hop's granted_scopes must be a subset of the + * preceding effective scopes. + * + * @generated from field: repeated host.authority.v1.WorkScopeV1 authority_scopes = 17; + */ + authorityScopes: WorkScopeV1[]; + + /** + * actor_chain is ordered from the first delegated actor to the current actor. + * The owner is not duplicated here merely to make a direct call look uniform. + * Every hop attenuates the one before it, except the final hop of a + * capability carrying grant_hop. + * + * @generated from field: repeated host.authority.v1.WorkActorV1 actor_chain = 18; + */ + actorChain: WorkActorV1[]; + + /** + * attribution_team_ids is an immutable verified attribution snapshot. It + * explains ownership; current authorization is still evaluated separately. + * + * @generated from field: repeated string attribution_team_ids = 19; + */ + attributionTeamIds: string[]; + + /** + * workspace_id is the workspace the task runs against, when the task is + * scoped to one. + * + * @generated from field: optional string workspace_id = 20; + */ + workspaceId?: string; + + /** + * project_id narrows workspace_id to a single project, when the task is + * scoped that far. + * + * @generated from field: optional string project_id = 21; + */ + projectId?: string; + + /** + * owner_principal_kind distinguishes the sort of principal the owner is, so + * a verifier can present the owner without resolving it against a directory. + * Optional on the wire: a capability minted before this field existed is + * still a valid capability, and an archived receipt embedding one still + * verifies. Deriving an identity from a capability that omits it is the + * error, raised where the identity is built. + * + * @generated from field: optional string owner_principal_kind = 22; + */ + ownerPrincipalKind?: string; + + /** + * owner_agent_id is the owner's agent manifest identity. Required when + * owner_principal_kind is "agent" and absent otherwise. + * + * @generated from field: optional string owner_agent_id = 23; + */ + ownerAgentId?: string; + + /** + * organization_id is the organization the task runs in. It is not the + * tenant: a tenant may hold several organizations, and authorization is + * scoped per organization. An actor hop may name a different one. + * + * @generated from field: optional string organization_id = 25; + */ + organizationId?: string; + + /** + * grant_hop is the approval grant this capability was minted under. It is + * the one audited exception to the attenuation rule: the final actor hop + * holds exactly granted_scope, which the preceding hop need not contain. + * Present only on a single-use child capability minted for one approved + * call; absent on every ordinary session. + * + * @generated from field: optional host.authority.v1.WorkGrantHopV1 grant_hop = 24; + */ + grantHop?: WorkGrantHopV1; + + /** + * seal binds this capability to one installation and one execution: the + * principal's epoch, the installation and revision it was minted for, and + * the build incarnation it was minted on. A verifier compares every field + * against the live value and refuses on any mismatch, which is what stops a + * capability outliving the installation or the build it was issued against. + * + * REQUIRED. An earlier version of this field was optional, with the stated + * reason that a schema rule would invalidate every archived capability and + * every receipt embedding one, so the requirement belonged in the verifier. + * Two independent reviews named that for what it is: a backward-compatibility + * hedge, which the rules in force forbid. It also meant every reader other + * than the verifier saw a capability's binding to its installation as + * optional, so the strongest check in the model was the easiest one for a + * consumer to not notice. + * + * Archived capabilities and receipts are historical DATA. If they must be + * read after this, they get a snapshot type of their own rather than keeping + * the live credential permanently weaker than it should be. + * + * @generated from field: host.authority.v1.WorkSealV1 seal = 26; + */ + seal?: WorkSealV1; + + /** + * operation_binding is the unit of authority this capability exercises, + * sealed by its id, revision and incarnation. Present on an operation + * context and absent on a session that exercises none. + * + * The id is what a verifier looks the binding up by, exactly. Nothing + * searches the bindings for one that contains the capability's scopes: a + * search is a predicate someone wrote, and a predicate one case too + * generous grants authority nobody reviewed. + * + * @generated from field: optional host.authority.v1.WorkOperationBindingV1 operation_binding = 27; + */ + operationBinding?: WorkOperationBindingV1; +}; + +/** + * Describes the message host.authority.v1.WorkContextV1. + * Use `create(WorkContextV1Schema)` to create a new message. + */ +export const WorkContextV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 0); + +/** + * WorkSealV1 binds a capability to one installation and one execution. Its + * principal_epoch is the TASK OWNER'S; an actor hop carries its own in + * WorkActorV1.principal_epoch, because an actor's authority is narrowed + * independently of the owner's. Every + * field is a value the issuer holds live and the verifier compares exactly, so + * a capability minted before an installation was revised, a principal's + * authority was reset, or a build was replaced stops verifying at that moment + * rather than at its own expiry. + * + * @generated from message host.authority.v1.WorkSealV1 + */ +export type WorkSealV1 = Message<"host.authority.v1.WorkSealV1"> & { + /** + * principal_epoch is the principal's current epoch. Advancing it + * invalidates every capability minted for that principal, which is how a + * compromised principal is cut off without waiting for expiry. + * + * @generated from field: uint64 principal_epoch = 1; + */ + principalEpoch: bigint; + + /** + * installation_id identifies one organization's installation of one module. + * Authority is held through an installation, so a capability that names none + * is bound to nothing. + * + * @generated from field: string installation_id = 2; + */ + installationId: string; + + /** + * installation_revision is the installation's revision at mint time. A + * verifier holding a different revision refuses: the scope of an + * installation changes with its revision, so a capability sealed to an + * earlier one asks for authority under terms that no longer apply. + * + * @generated from field: uint64 installation_revision = 3; + */ + installationRevision: bigint; +}; + +/** + * Describes the message host.authority.v1.WorkSealV1. + * Use `create(WorkSealV1Schema)` to create a new message. + */ +export const WorkSealV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 1); + +/** + * WorkOperationBindingV1 is the unit of authority an operation context + * exercises, sealed so that a verifier resolves exactly one binding and + * compares it rather than deciding which binding the capability's scopes fit. + * + * @generated from message host.authority.v1.WorkOperationBindingV1 + */ +export type WorkOperationBindingV1 = Message<"host.authority.v1.WorkOperationBindingV1"> & { + /** + * binding_id is the host's identifier for the binding. The verifier looks it + * up EXACTLY: nothing searches the bindings for one that fits a capability's + * scopes, because a search is a predicate somebody wrote and a predicate one + * case too generous grants authority nobody reviewed. + * + * This comment used to say the id "is never derived from the binding's + * contents, because a derived id is one a caller can compute for a binding + * it was never granted". I refuted a review finding against that sentence by + * reading it in isolation and judging it correct. The reviewer was right and + * I was wrong: solutionhost/authority.go says the opposite in the package + * that owns the id — deriving it deterministically is delivery's business + * and better than random, and "predictability costs nothing here: an id is + * neither a secret nor a capability". + * + * Predictability costs nothing because ENTITLEMENT is what refuses a binding + * a caller does not hold, not obscurity: the verifier requires the resolved + * binding to be granted to the exercising principal within the installation + * the capability is sealed to. Guessing an id gets you a refusal. Resting + * the rule on unguessability was the retracted reasoning, and leaving it + * here contradicted the package it describes. + * + * @generated from field: string binding_id = 1; + */ + bindingId: string; + + /** + * revision is the binding's revision at mint time. A verifier holding a + * different revision refuses. + * + * @generated from field: uint64 revision = 2; + */ + revision: bigint; + + /** + * incarnation is the binding's incarnation at mint time, which changes when + * the binding is re-established rather than merely revised. + * + * @generated from field: uint64 incarnation = 3; + */ + incarnation: bigint; +}; + +/** + * Describes the message host.authority.v1.WorkOperationBindingV1. + * Use `create(WorkOperationBindingV1Schema)` to create a new message. + */ +export const WorkOperationBindingV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 2); + +/** + * WorkScopeV1 is a structured, product-neutral capability scope. Empty + * resource_ids means every resource of resource_kind; a child may narrow that + * wildcard to explicit IDs but may never widen an explicit parent set. + * + * @generated from message host.authority.v1.WorkScopeV1 + */ +export type WorkScopeV1 = Message<"host.authority.v1.WorkScopeV1"> & { + /** + * resource_kind is the class of resource the scope grants against. + * + * @generated from field: string resource_kind = 1; + */ + resourceKind: string; + + /** + * actions are the operations permitted on that kind. + * + * @generated from field: repeated string actions = 2; + */ + actions: string[]; + + /** + * resource_ids narrows the scope to specific resources. Empty means every + * resource of resource_kind. + * + * @generated from field: repeated string resource_ids = 3; + */ + resourceIds: string[]; +}; + +/** + * Describes the message host.authority.v1.WorkScopeV1. + * Use `create(WorkScopeV1Schema)` to create a new message. + */ +export const WorkScopeV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 3); + +/** + * WorkActorV1 is one verified delegated actor. granted_scopes are the actor's + * effective scopes and must monotonically attenuate the previous hop. + * + * @generated from message host.authority.v1.WorkActorV1 + */ +export type WorkActorV1 = Message<"host.authority.v1.WorkActorV1"> & { + /** + * principal_id identifies the actor this hop delegated to. + * + * @generated from field: string principal_id = 1; + */ + principalId: string; + + /** + * principal_kind distinguishes the sort of principal, so a human and an + * agent bearing the same id are not conflated. + * + * @generated from field: string principal_kind = 2; + */ + principalKind: string; + + /** + * delegation_id identifies the delegation that produced this hop, so the + * chain stays auditable back to its grant. + * + * @generated from field: string delegation_id = 3; + */ + delegationId: string; + + /** + * granted_scopes are this actor's effective scopes, a subset of the + * preceding hop's. + * + * @generated from field: repeated host.authority.v1.WorkScopeV1 granted_scopes = 4; + */ + grantedScopes: WorkScopeV1[]; + + /** + * agent_id is the actor's agent manifest identity. Required when + * principal_kind is "agent" and absent otherwise. + * + * @generated from field: optional string agent_id = 5; + */ + agentId?: string; + + /** + * organization_id is the organization this actor belongs to, when it is not + * the one the task runs in. An org-bridge agent acts in an organization the + * owner does not belong to, and authorization is scoped to the actor's own. + * + * @generated from field: optional string organization_id = 6; + */ + organizationId?: string; + + /** + * principal_epoch is THIS actor's epoch, distinct from the owner's epoch in + * the seal. Advancing it invalidates every capability in which this + * principal is an actor, without touching the owner's. + * + * It exists because the seal's epoch is the task owner's, and an actor's + * authority can be narrowed independently of the owner's: a delegated + * operation context may have a person as its owner and a service principal + * as its actor, and narrowing that service principal must reach the + * capabilities it acts in. Without this field the only lever for a + * compromised actor is the tenant's authorization_revision, which cuts off + * every capability of the tenant. + * + * REQUIRED, for the reason seal gives. A hop with no epoch is a principal + * nothing can revoke, and leaving that expressible on the wire made it a + * shape a consumer could mint without noticing. + * + * @generated from field: uint64 principal_epoch = 7; + */ + principalEpoch: bigint; +}; + +/** + * Describes the message host.authority.v1.WorkActorV1. + * Use `create(WorkActorV1Schema)` to create a new message. + */ +export const WorkActorV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 4); + +/** + * WorkGrantHopV1 records the approval that justifies a capability holding + * authority its delegating owner never held. It is minted only as a new child + * capability bound to one tool, one subject and one call, so the authority it + * adds is unusable anywhere else and expires with the grant window. + * + * @generated from message host.authority.v1.WorkGrantHopV1 + */ +export type WorkGrantHopV1 = Message<"host.authority.v1.WorkGrantHopV1"> & { + /** + * grant_id identifies the approval grant, so revoking the grant and + * auditing the call both reach the same record. + * + * @generated from field: string grant_id = 1; + */ + grantId: string; + + /** + * approvers are the principals whose decision produced the grant, every one + * of an N-of-M quorum, so the audit record is complete. + * + * @generated from field: repeated host.authority.v1.WorkApproverV1 approvers = 2; + */ + approvers: WorkApproverV1[]; + + /** + * granted_scope is exactly what the approval added: one resource_kind, one + * action and one resource_id. A grant never widens beyond that triple. + * + * @generated from field: host.authority.v1.WorkScopeV1 granted_scope = 3; + */ + grantedScope?: WorkScopeV1; + + /** + * subject is what the grant is pinned to, in the approvals engine's own + * vocabulary, so a grant approved for one subject cannot be spent on another. + * + * @generated from field: string subject = 4; + */ + subject: string; + + /** + * request_digest binds the grant to the exact call the approver saw. + * + * @generated from field: string request_digest = 5; + */ + requestDigest: string; +}; + +/** + * Describes the message host.authority.v1.WorkGrantHopV1. + * Use `create(WorkGrantHopV1Schema)` to create a new message. + */ +export const WorkGrantHopV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 5); + +/** + * WorkApproverV1 is one principal whose decision produced a grant. It carries + * the kind as well as the id: a policy that requires a human approver cannot + * be written against bare identifiers. + * + * @generated from message host.authority.v1.WorkApproverV1 + */ +export type WorkApproverV1 = Message<"host.authority.v1.WorkApproverV1"> & { + /** + * principal_id identifies the approver. + * + * @generated from field: string principal_id = 1; + */ + principalId: string; + + /** + * principal_kind distinguishes the sort of principal the approver is. + * + * @generated from field: string principal_kind = 2; + */ + principalKind: string; +}; + +/** + * Describes the message host.authority.v1.WorkApproverV1. + * Use `create(WorkApproverV1Schema)` to create a new message. + */ +export const WorkApproverV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 6); + +/** + * ApprovalRequiredV1 is the signal a policy decision point returns instead of + * a denial when the call is approvable: the authority is not held, but an + * approver may grant it. It names exactly what a WorkGrantHopV1 would have to + * carry, so a decision and the capability that satisfies it are the same shape. + * It is carried as a typed error detail on a FailedPrecondition status. + * + * @generated from message host.authority.v1.ApprovalRequiredV1 + */ +export type ApprovalRequiredV1 = Message<"host.authority.v1.ApprovalRequiredV1"> & { + /** + * request_id identifies the approval request the engine created, which the + * caller waits on and the resulting grant refers back to. + * + * @generated from field: string request_id = 1; + */ + requestId: string; + + /** + * requested_scope is the authority the call needs and the principal lacks. + * + * @generated from field: host.authority.v1.WorkScopeV1 requested_scope = 2; + */ + requestedScope?: WorkScopeV1; + + /** + * subject is what a grant would be pinned to. + * + * @generated from field: string subject = 3; + */ + subject: string; + + /** + * request_digest is the exact call put to the approver. + * + * @generated from field: string request_digest = 4; + */ + requestDigest: string; + + /** + * audience is the tool a granted capability must be minted for. + * + * @generated from field: string audience = 5; + */ + audience: string; +}; + +/** + * Describes the message host.authority.v1.ApprovalRequiredV1. + * Use `create(ApprovalRequiredV1Schema)` to create a new message. + */ +export const ApprovalRequiredV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_authority_v1_work_context, 7); + diff --git a/libraries/authority-client/typescript/src/gen/host/composition/v1/composition_pb.ts b/libraries/authority-client/typescript/src/gen/host/composition/v1/composition_pb.ts new file mode 100644 index 00000000..eab14d07 --- /dev/null +++ b/libraries/authority-client/typescript/src/gen/host/composition/v1/composition_pb.ts @@ -0,0 +1,462 @@ +// @generated by protoc-gen-es v2.11.0 with parameter "target=ts,import_extension=js" +// @generated from file host/composition/v1/composition.proto (package host.composition.v1, syntax proto3) +/* eslint-disable */ + +// The composition interface: how the host learns what is composed. One +// operation. The render produces a manifest per module instance; the host +// derives from it the module's principal, its ceilings and its bindings. There +// is no envelope: the ceiling is the manifest. + +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2"; +import type { WorkScopeV1 } from "../../authority/v1/work_context_pb.js"; +import { file_host_authority_v1_work_context } from "../../authority/v1/work_context_pb.js"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file host/composition/v1/composition.proto. + */ +export const file_host_composition_v1_composition: GenFile = /*@__PURE__*/ + fileDesc("CiVob3N0L2NvbXBvc2l0aW9uL3YxL2NvbXBvc2l0aW9uLnByb3RvEhNob3N0LmNvbXBvc2l0aW9uLnYxItUBChRBcHBseU1hbmlmZXN0UmVxdWVzdBI3CghtYW5pZmVzdBgBIAEoCzIlLmhvc3QuY29tcG9zaXRpb24udjEuTW9kdWxlTWFuaWZlc3RWMRI2CgdjYXJyaWVyGAIgASgLMiUuaG9zdC5jb21wb3NpdGlvbi52MS5TaWduZWRNYW5pZmVzdFYxEhIKCmNyZWRlbnRpYWwYAyABKAkSOAoJYXV0aG9yaXR5GAQgASgLMiUuaG9zdC5jb21wb3NpdGlvbi52MS5TaWduZWRNYW5pZmVzdFYxIvEBChNBdXRob3JpdHlNYW5pZmVzdFYxEg4KBm1vZHVsZRgBIAEoCRISCgpnZW5lcmF0aW9uGAIgASgEEhwKFGNvcmVfbWFuaWZlc3RfZGlnZXN0GAMgASgJEjQKB21ldGhvZHMYBCADKAsyIy5ob3N0LmNvbXBvc2l0aW9uLnYxLk1ldGhvZFBvbGljeVYxEjYKDnNjb3BlX2NlaWxpbmdzGAUgAygLMh4uaG9zdC5hdXRob3JpdHkudjEuV29ya1Njb3BlVjESKgoFcm9sZXMYBiADKAsyGy5ob3N0LmNvbXBvc2l0aW9uLnYxLlJvbGVWMSJuCg5NZXRob2RQb2xpY3lWMRIOCgZtZXRob2QYASABKAkSMAoIcmVxdWlyZXMYAiADKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMRIaChJhbnlfY2hlY2tlZF9jYWxsZXIYAyABKAgiNgoQU2lnbmVkTWFuaWZlc3RWMRIQCghkb2N1bWVudBgBIAEoDBIQCghlbnZlbG9wZRgCIAEoDCJYChVBcHBseU1hbmlmZXN0UmVzcG9uc2USEQoJcHJpbmNpcGFsGAEgASgJEhIKCmdlbmVyYXRpb24YAiABKAQSGAoQaW5zdGFsbGF0aW9uX2lkcxgDIAMoCSKdAgoQTW9kdWxlTWFuaWZlc3RWMRIOCgZtb2R1bGUYASABKAkSEQoJcHJpbmNpcGFsGAIgASgJEgwKBGtpbmQYAyABKAkSEgoKZ2VuZXJhdGlvbhgEIAEoBBIwCghiaW5kaW5ncxgFIAMoCzIeLmhvc3QuY29tcG9zaXRpb24udjEuQmluZGluZ1YxEjsKDnJlc291cmNlX2tpbmRzGAYgAygLMiMuaG9zdC5jb21wb3NpdGlvbi52MS5SZXNvdXJjZUtpbmRWMRIpCgRwYWdlGAcgASgLMhsuaG9zdC5jb21wb3NpdGlvbi52MS5QYWdlVjESKgoFcm9sZXMYCCADKAsyGy5ob3N0LmNvbXBvc2l0aW9uLnYxLlJvbGVWMSJGCgZSb2xlVjESDAoEbmFtZRgBIAEoCRIuCgZzY29wZXMYAiADKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMSLQAQoJQmluZGluZ1YxEgoKAmlkGAEgASgJEhAKCGF1ZGllbmNlGAIgASgJEjUKDWludm9rZV9zY29wZXMYAyADKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMRI3Cg9oZWFkbGVzc19zY29wZXMYBCADKAsyHi5ob3N0LmF1dGhvcml0eS52MS5Xb3JrU2NvcGVWMRI1Cg1sb29rdXBfc2NvcGVzGAUgAygLMh4uaG9zdC5hdXRob3JpdHkudjEuV29ya1Njb3BlVjEiLwoOUmVzb3VyY2VLaW5kVjESDAoEa2luZBgBIAEoCRIPCgdhY3Rpb25zGAIgAygJIiYKBlBhZ2VWMRINCgV0aXRsZRgBIAEoCRINCgVvcmRlchgCIAEoBTJ8ChJDb21wb3NpdGlvblNlcnZpY2USZgoNQXBwbHlNYW5pZmVzdBIpLmhvc3QuY29tcG9zaXRpb24udjEuQXBwbHlNYW5pZmVzdFJlcXVlc3QaKi5ob3N0LmNvbXBvc2l0aW9uLnYxLkFwcGx5TWFuaWZlc3RSZXNwb25zZUIzWjFnYXRld2F5L3BrZy9nZW4vaG9zdC9jb21wb3NpdGlvbi92MTtjb21wb3NpdGlvbnYxYgZwcm90bzM", [file_host_authority_v1_work_context]); + +/** + * ApplyManifestRequest carries the manifest. + * + * @generated from message host.composition.v1.ApplyManifestRequest + */ +export type ApplyManifestRequest = Message<"host.composition.v1.ApplyManifestRequest"> & { + /** + * The sketch of a manifest, kept through the transition. An implementation + * that verifies deliveries ignores it when a carrier is present. + * + * @generated from field: host.composition.v1.ModuleManifestV1 manifest = 1; + */ + manifest?: ModuleManifestV1; + + /** + * The delivery as Codefly signs it: core's module manifest and the DSSE + * envelope over it. An implementation verifies the envelope against the release + * keys it pins and reads the manifest from the verified document, never from + * the request, so what composes a module is the same signed document on the + * local authority and on the host. + * + * @generated from field: host.composition.v1.SignedManifestV1 carrier = 2; + */ + carrier?: SignedManifestV1; + + /** + * The credential of the workload delivering the manifest, as that + * implementation attests workloads: the launcher's on the local authority, the + * delivery service account's on the host. A manifest is delivered by its own + * module's delivery workload and by nothing else. + * + * @generated from field: string credential = 3; + */ + credential: string; + + /** + * The authority's own document for this delivery, an AuthorityManifestV1: + * what the module declares that the authority enforces and core's manifest + * does not carry. Signed in the same envelope format by the same key as + * carrier, and naming carrier's digest. Absent means the module declares no + * method policy, and every Check that names one of its methods is refused. + * + * @generated from field: host.composition.v1.SignedManifestV1 authority = 4; + */ + authority?: SignedManifestV1; +}; + +/** + * Describes the message host.composition.v1.ApplyManifestRequest. + * Use `create(ApplyManifestRequestSchema)` to create a new message. + */ +export const ApplyManifestRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_composition_v1_composition, 0); + +/** + * AuthorityManifestV1 is the authority's document for one delivery. + * + * @generated from message host.composition.v1.AuthorityManifestV1 + */ +export type AuthorityManifestV1 = Message<"host.composition.v1.AuthorityManifestV1"> & { + /** + * The module, as the core manifest it travels with names it. + * + * @generated from field: string module = 1; + */ + module: string; + + /** + * The generation, equal to that core manifest's. + * + * @generated from field: uint64 generation = 2; + */ + generation: bigint; + + /** + * "sha256:" of the core manifest document delivered with it. + * + * @generated from field: string core_manifest_digest = 3; + */ + coreManifestDigest: string; + + /** + * Every method the module's published contracts serve, with what each + * declares. A method that declares nothing is listed with neither field set. + * + * @generated from field: repeated host.composition.v1.MethodPolicyV1 methods = 4; + */ + methods: MethodPolicyV1[]; + + /** + * The module's own resource kinds with the actions its contract declares on + * each (its scope ceilings). Core's manifest names the kinds alone, so without + * these a kind serves any action and a person's ask for everything they hold + * there cannot be enumerated. Each names a kind core's manifest declares. + * + * @generated from field: repeated host.authority.v1.WorkScopeV1 scope_ceilings = 5; + */ + scopeCeilings: WorkScopeV1[]; + + /** + * The roles a solution declares a person may hold on an installation of it, + * as ModuleManifestV1.roles declares them through the sketch: each within + * the solution's own scope ceilings or explicit invoke/lookup binding scopes, + * one of them installer. Headless-only scopes cannot supply a role grant. + * Core's manifest carries no roles, so they travel here until it does. A + * module declares none; a module's delivery listing any is refused. + * + * @generated from field: repeated host.composition.v1.RoleV1 roles = 6; + */ + roles: RoleV1[]; +}; + +/** + * Describes the message host.composition.v1.AuthorityManifestV1. + * Use `create(AuthorityManifestV1Schema)` to create a new message. + */ +export const AuthorityManifestV1Schema: GenMessage = /*@__PURE__*/ + messageDesc(file_host_composition_v1_composition, 1); + +/** + * MethodPolicyV1 is what a call to one method must hold, as the module's + * contract declares it with the authority.hop.v1.policy option. + * + * @generated from message host.composition.v1.MethodPolicyV1 + */ +export type MethodPolicyV1 = Message<"host.composition.v1.MethodPolicyV1"> & { + /** + * The method: "/package.Service/Method" for a gRPC method, or an HTTP route + * "