Skip to content

Add Asqav Sign Action tool node#6614

Open
jagmarques wants to merge 1 commit into
FlowiseAI:mainfrom
jagmarques:asqav/asqav-listing
Open

Add Asqav Sign Action tool node#6614
jagmarques wants to merge 1 commit into
FlowiseAI:mainfrom
jagmarques:asqav/asqav-listing

Conversation

@jagmarques

Copy link
Copy Markdown

This adds a new tool node for Asqav, a service that lets you sign AI agent actions with post-quantum cryptographic compliance receipts.

What it does

The node takes an action type and optional context, then calls the Asqav API to produce a signed compliance receipt. It returns the signature ID, action ID, verification URL, timestamp, and signing algorithm. This is useful for audit trails on autonomous agent decisions.

The node uses direct fetch calls to the Asqav REST API. It has no third-party SDK dependency, so there is nothing extra to install or bundle.

Files

  • nodes/tools/AsqavSignAction/AsqavSignAction.ts - the tool node
  • nodes/tools/AsqavSignAction/asqav.svg - icon
  • credentials/AsqavApi.credential.ts - API key credential (uses type: 'password' per the credential security guide)

Setup

Users create an Asqav account at asqav.com, generate an API key in the dashboard, and connect it through the new "Asqav API" credential. No other configuration is needed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the Asqav API credential and the Asqav Sign Action tool, allowing users to sign agent actions and obtain cryptographic compliance receipts. Feedback on the implementation highlights several key improvements: addressing a potential SSRF vulnerability by validating the user-configurable baseUrl against a deny list, validating the presence of the API key early, using the robust parseJsonBody utility instead of standard JSON.parse, and optimizing the workflow by allowing an optional agentId to prevent creating a new agent on every execution.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

}
}

const baseUrl = ((nodeData.inputs?.baseUrl as string) || DEFAULT_BASE_URL).replace(/\/+$/, '')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

Since baseUrl is a user-configurable input, an attacker could supply an internal IP address or hostname (e.g., http://127.0.0.1 or AWS metadata endpoints) to perform a Server-Side Request Forgery (SSRF) attack. Call await checkDenyList(baseUrl) to validate the URL against Flowise's security policy before making any network requests.

        const baseUrl = ((nodeData.inputs?.baseUrl as string) || DEFAULT_BASE_URL).replace(/\n+$/, '')
        await checkDenyList(baseUrl)

Comment on lines +1 to +2
import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getCredentialData, getCredentialParam } from '../../../src/utils'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Import parseJsonBody from ../../../src/utils to allow robust JSON parsing of the context input, and import checkDenyList from ../../../src/httpSecurity to protect against SSRF vulnerabilities.

import { ICommonObject, INode, INodeData, INodeParams } from '../../../src/Interface'
import { getCredentialData, getCredentialParam, parseJsonBody } from '../../../src/utils'
import { checkDenyList } from '../../../src/httpSecurity'

Comment on lines +61 to +62
const credentialData = await getCredentialData(nodeData.credential ?? '', options ?? {})
const apiKey = getCredentialParam('asqavApiKey', credentialData, nodeData)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Validate that the apiKey is present before proceeding. If it is missing, throw an error early to provide a clear and helpful error message to the user.

        const credentialData = await getCredentialData(nodeData.credential ?? '', options ?? {})
        const apiKey = getCredentialParam('asqavApiKey', credentialData, nodeData)
        if (!apiKey) {
            throw new Error('Asqav Sign Action: API Key is required. Please configure the Asqav API credential.')
        }
References
  1. When a feature requires a specific configuration (e.g., an API key), it is preferable to throw an error if the configuration is missing rather than silently falling back to a different implementation.

Comment on lines +75 to +79
try {
context = JSON.parse(trimmed)
} catch {
throw new Error('Asqav Sign Action: "Context" must be valid JSON.')
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Use parseJsonBody instead of JSON.parse. parseJsonBody is a robust utility in Flowise that handles common JSON formatting issues such as trailing commas, single quotes, and comments, providing a much better user experience.

                    try {
                        context = parseJsonBody(trimmed)
                    } catch {
                        throw new Error('Asqav Sign Action: "Context" must be valid JSON.')
                    }

Comment on lines +92 to +107
const agentResponse = await fetch(`${baseUrl}/agents/create`, {
method: 'POST',
headers,
body: JSON.stringify({
name: 'flowise',
algorithm: 'ml-dsa-65',
capabilities: []
})
})
if (!agentResponse.ok) {
const detail = await agentResponse.text().catch(() => '')
throw new Error(
`Asqav Sign Action: agent create failed (${agentResponse.status} ${agentResponse.statusText})${detail ? `: ${detail}` : ''}`
)
}
const agent = (await agentResponse.json()) as { agent_id: string }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Creating a new agent via /agents/create on every single execution of the tool is highly inefficient and will clutter the user's Asqav account with many ephemeral agents named 'flowise'. Consider adding an optional agentId input parameter. If provided, the tool can skip the agent creation step and directly call /agents/${agentId}/sign, which also reduces the number of API roundtrips from two to one.

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.

1 participant