Skip to content

feat(vt-flow): admin API for onboarding-process flow#430

Open
tarunvadde wants to merge 37 commits into
mainfrom
feat/vt-flow-validation-process
Open

feat(vt-flow): admin API for onboarding-process flow#430
tarunvadde wants to merge 37 commits into
mainfrom
feat/vt-flow-validation-process

Conversation

@tarunvadde

@tarunvadde tarunvadde commented May 1, 2026

Copy link
Copy Markdown
Contributor

Implements the basic onboarding-process flow (the old "validation process", renamed in #457 in the SDK, plus the admin endpoint to drive it, migrated to the V4 chain. First slice of the admin API from #425, covering #426.

What's in it:

  • Validator admin endpoint: POST /v1/vt/flows/{participant_session_id}/validate. It looks up the flow's participant on the indexer, signs the credential, marks the participant validated on-chain, and offers it over Issue Credential V2. No start or accept endpoint on purpose: the flow starts from an on-chain event (indexer-driven) and acceptance is automatic, so neither belongs in the admin API.
  • VtFlowOrchestrator running the flow: start -> onboarding-request -> validate -> credential offer -> accept -> publish as a LinkedVP.
  • V4 chain migration: VeranaChainService and its types moved to the V4 pp/ec/co message (participant/ecosystem/corporation), sourced from the verana-types dev.16 alias already on main, so no dependency bump. The chain calls the flow uses (get participant, set validated) work on the deployed V4 devnet.
  • Digest fix: the applicant's credential digest is now computed over the credential content with the proof excluded, so it's independent of the signature Credo adds at issuance. A spec clarification to formalize the digest definition will follow in verana-spec.
  • Plugin wiring (VtFlowNestPlugin), the record DTO, and swagger.

Deferred to the V4 phase: creating the on-chain ParticipantSession. The old agent-id blocker (#289/#340) is fixed on V4 (#342, VS-to-VS 0/0 sessions are now valid), but a separate V4 authz constraint means it needs a second vs-operator account, see the comment below.

The V4 chain calls (validate, get participant) were verified against a local V4 node.

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
@tarunvadde tarunvadde requested review from genaris and lotharking May 1, 2026 12:21
Comment thread packages/agent-sdk/src/blockchain/VeranaChainService.ts
Comment thread apps/vs-agent/src/controllers/admin/vt-flow/dto/validate-flow.dto.ts Outdated
Comment thread apps/vs-agent/src/controllers/admin/vt-flow/VtFlowsService.ts Outdated
…dto.ts

Co-authored-by: andresfv95 <andresfelipe083195@hotmail.com>
'Applicant action. Runs `start-perm-vp` on-chain, opens an implicit DIDComm connection to the validator, and dispatches the vt-flow `validation-request`.',
})
@ApiCreatedResponse({ type: VtFlowRecordDto })
public startValidationProcess(@Body() body: StartValidationProcessDto): Promise<VtFlowRecordDto> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @genaris, I'm not completely sure about it.
When we start the validation process, does the agent require us to do this? My question comes from the frontend perspective (and also the ledger), where it's common to initiate the process from there; the flow usually starts on that side. On the other hand, the agent seems to just listen to the indexer WebSocket and then begins sending the DIDComm connect.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. The current PR follows the explicit ask in #426:

"The flow will start at the Applicant VS Agent, by calling an Admin API
method (following the ideas from #425, it can be a POST /v1/vt-flows)"

So the agent owning the flow start is what the issue spec'd. The
frontend-driven alternative you mention is also a valid pattern (frontend
broadcasts start-perm-vp itself, agent reacts to the indexer event), but
it's a scope shift. I'll let @genaris confirm which model is preferred.
Happy to rework if Ariel wants the indexer-event-driven path instead.


/** Permission type values per `verana.perm.v1.PermissionType`. */
export const PermissionType = {
UNSPECIFIED: 0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer not mapping this state, this throw and error if it isn't a valid state

Suggested change
UNSPECIFIED: 0,

const claims = (record.claims ?? {}) as JsonObject
const unsignedCredential = createCredential({
id: `${agent.did}#${utils.uuid()}`,
type: input.credentialType ?? ['VerifiableCredential', 'VerifiableTrustCredential'],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure; this could be error-prone. Let's leave it as an input attribute since it's part of the validations; for now, I'd prefer the default one

)
const digest = generateDigestSRI(JSON.stringify(signed.jsonCredential))

await chain.setPermissionVPToValidated({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about error control or a logger? This step could fail, and we need to control this.

did: string,
validatorPermId: number,
): Promise<Permission | undefined> {
const perms = await chain.findPermissionsWithDID({ did })

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This validation againt the indexer to avoid sync problems

permId: String(holderPerm.id),
agentPermId: '0',
walletAgentPermId: '0',
claims: input.claims,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claims need to be validated against the schema again before sending them to vtFlow

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading §5.1 step 3 in #402, claim validation is on the validator side:

"The applicant MAY also include credential claims [...] The validator
MUST either accept the information and proceed, or refuse it with an
error code and descriptive error message."

So the validator is the one that validates claims and rejects bad ones.
For Phase 0 we're keeping that responsibility on the validator.

Adding applicant-side pre-validation as a nice-to-have is doable (fetch the
schema from the indexer, run JSON-schema validation with ajv), but it's
extra work outside the minimum scope of #426. Happy to add it as a follow-up
issue if you'd prefer that flow.

JsonTransformer.fromJSON(unsignedCredential, W3cCredential),
verificationMethodId,
)
const digest = generateDigestSRI(JSON.stringify(signed.jsonCredential))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember, this needs to be checked on the validator side

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify what you mean? Line 142 IS the validator-side digest
computation per §5.1 step 6 ("The validator generates and signs the
credential, and computes the digest"). The applicant-side check happens
later at step 9 when the applicant verifies the digest matches what's on
the chain.

Did you mean the validator should also re-verify the digest before
broadcasting set-perm-vp-validated, or something else? Want to make sure
I'm reading this right.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember, once the credential has been valid, you must include the credential in the DID Document

@genaris genaris linked an issue May 4, 2026 that may be closed by this pull request
@lotharking

Copy link
Copy Markdown
Collaborator

Hey @tarunvadde, is this PR ready for review?

@tarunvadde

Copy link
Copy Markdown
Contributor Author

Hey @tarunvadde, is this PR ready for review?

Yes, once #442 is merged into feat/vt-flow-validation-process. This PR is ready for review.

tarunvadde and others added 8 commits May 26, 2026 01:19
…riven

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
…is automatic

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
…pant_session_id

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
… issuance to orchestrator

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
…on-process

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>

# Conflicts:
#	apps/vs-agent/src/main.ts
#	apps/vs-agent/tests/__mocks__/helpers.ts
#	packages/agent-sdk/src/index.ts
#	packages/agent-sdk/src/utils/index.ts
…442)

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
tarunvadde and others added 5 commits June 17, 2026 01:12
… into feat/vt-flow-validation-process

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
@tarunvadde tarunvadde changed the title feat(vt-flow): admin API for 5.1 validation process flow feat(vt-flow): admin API for onboarding-process flow Jun 18, 2026
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
@tarunvadde

tarunvadde commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

@genaris

This implements #426 and #425 Phase 0: the basic onboarding-process flow plus the validate admin endpoint, on the current V3 chain (which is what #426 asks for, "current VS Agent status as is"). Builds and unit tests pass, and the flow was validated end to end against the devnet while it was still on V3.

The devnet has since moved to V4, so a live re-run now needs the V4 chain migration (pp/ec/co plus the Corporation auth model). That's the next phase's work, not this PR. I did prototype it against a local V4 node and confirmed the hard parts work: the Corporation bootstrap, the group-proposal operator grant, and the ecosystem/schema ops. One thing worth carrying into the V4 issues: OperatorAuthorization and VSOperatorAuthorization are mutually exclusive per (corporation, operator), so the agent needs a separate vs-operator account, which matches the spec. Happy to feed the prototype and findings in.

Could you confirm the plan: land this as the V3 basic flow now, and handle V4 as the organized effort in the next PR?

…on-process

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>

# Conflicts:
#	packages/agent-sdk/src/blockchain/IndexerWebSocketService.ts
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
@tarunvadde

tarunvadde commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Scope update: this PR is now the V4 chain migration, the digest fix, and the validate admin endpoint. Creating the on-chain session is left for the next phase.

Why the session is deferred: I ran the full flow against a local V4 node and everything works except the session. On the current chain, marking a participant validated (OperatorAuthorization) and creating its session (VSOperatorAuthorization) need two different account permissions, and the two can't sit on the same account. So the agent would need a second account just for the session. The spec actually expects one account to do both (both under AUTHZ-CHECK-3), so this is the chain catching up, not a problem with the agent. I have a working prototype of the two-account path (green end to end on a V4 node) ready to feed into the V4 work.

Two findings worth carrying over:

@lotharking lotharking left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please review the nomenclature according to the specification you are using. If it is v4, replace "permission" with "participant" and "trust registry" with "ecosystem".

Comment thread packages/agent-sdk/src/blockchain/handlers/stateMutations.ts Outdated
Comment thread packages/agent-sdk/src/blockchain/handlers/stateMutations.ts Outdated
tarunvadde and others added 3 commits June 19, 2026 19:40
Co-authored-by: andresfv95 <andresfelipe083195@hotmail.com>
Co-authored-by: andresfv95 <andresfelipe083195@hotmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
@tarunvadde

Copy link
Copy Markdown
Contributor Author

Please review the nomenclature according to the specification you are using. If it is v4, replace "permission" with "participant" and "trust registry" with "ecosystem".

I aligned the flow-level names here but kept the full sweep out of this PR on purpose. The chain layer (VeranaChainService) still uses the old method names like getPermission and setPermissionVPToValidated, it works as an adapter that maps them to the V4 participant messages, so the flow runs without renaming every caller. The indexer/sync side (the TrustRegistry and Permission types) is also still V3-named. Renaming all of that to participant/ecosystem is a systematic SDK-wide change, and I think it fits better with the rest of the V4 migration (the same phase as the on-chain session that's deferred here) than half-doing it in this flow PR. This PR is the basic flow plus the minimal V4 message migration to make it run.

@genaris

genaris commented Jun 19, 2026

Copy link
Copy Markdown
Member

Please review the nomenclature according to the specification you are using. If it is v4, replace "permission" with "participant" and "trust registry" with "ecosystem".

I aligned the flow-level names here but kept the full sweep out of this PR on purpose. The chain layer (VeranaChainService) still uses the old method names like getPermission and setPermissionVPToValidated, it works as an adapter that maps them to the V4 participant messages, so the flow runs without renaming every caller. The indexer/sync side (the TrustRegistry and Permission types) is also still V3-named. Renaming all of that to participant/ecosystem is a systematic SDK-wide change, and I think it fits better with the rest of the V4 migration (the same phase as the on-chain session that's deferred here) than half-doing it in this flow PR. This PR is the basic flow plus the minimal V4 message migration to make it run.

I agree about limiting the scope of the PRs, but at the moment it is hard to evaluate when so many things are "half done". Can we proceed on updating the SDK-wide change in a separate PR, and adapt this one once the other one is merged? We can move to the latest verana-types dev version (currently v0.10.1-dev.16) so we don't need to keep mixing versions between the testing and the production code.

Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Signed-off-by: Tarun Vadde <vaddeofficial@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validation Process Flow implementation (basic, VS Agent SDK level)

3 participants