Skip to content

Commit 69e0dc2

Browse files
committed
feat: update security requirements (PROVCON-5343)
1 parent 921ffe9 commit 69e0dc2

8 files changed

Lines changed: 168 additions & 0 deletions

File tree

packages/apidom-ls/src/config/a2a/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import httpAuthSecuritySchemeMeta from './http-auth-security-scheme/meta.ts';
1717
import oauth2SecuritySchemeMeta from './oauth2-security-scheme/meta.ts';
1818
import openIdConnectSecuritySchemeMeta from './open-id-connect-security-scheme/meta.ts';
1919
import mutualTlsSecuritySchemeMeta from './mutual-tls-security-scheme/meta.ts';
20+
import securityRequirementMeta from './security-requirement/meta.ts';
2021
import ApilintCodes from '../codes.ts';
2122

2223
export default {
@@ -49,4 +50,5 @@ export default {
4950
oauth2SecurityScheme: oauth2SecuritySchemeMeta,
5051
openIdConnectSecurityScheme: openIdConnectSecuritySchemeMeta,
5152
mutualTlsSecurityScheme: mutualTlsSecuritySchemeMeta,
53+
securityRequirement: securityRequirementMeta,
5254
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {
2+
ApidomCompletionItem,
3+
CompletionFormat,
4+
CompletionType,
5+
} from '../../../apidom-language-types.ts';
6+
import { A2A1 } from '../target-specs.ts';
7+
8+
const completion: ApidomCompletionItem[] = [
9+
{
10+
label: 'schemes',
11+
insertText: 'schemes',
12+
kind: 14,
13+
format: CompletionFormat.OBJECT,
14+
type: CompletionType.PROPERTY,
15+
insertTextFormat: 2,
16+
documentation: {
17+
kind: 'markdown',
18+
value:
19+
"Map of security scheme names to arrays of required scopes. Each key is a security scheme name from the Agent Card's `securitySchemes`, and each value is a list of required OAuth2 scopes (or an empty list if not applicable).",
20+
},
21+
targetSpecs: A2A1,
22+
},
23+
];
24+
25+
export default completion;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { A2A1 } from '../target-specs.ts';
2+
3+
/**
4+
* Hover documentation for A2A v1 SecurityRequirement fields.
5+
* See [SecurityRequirement](https://a2a-protocol.org/latest/definitions/#security-requirement).
6+
*/
7+
const documentation = [
8+
{
9+
target: 'schemes',
10+
docs: "Map of security scheme names to arrays of required scopes. Each key is a security scheme name from the Agent Card's `securitySchemes`, and each value is a list of required OAuth2 scopes (or an empty list if not applicable).",
11+
targetSpecs: A2A1,
12+
},
13+
];
14+
15+
export default documentation;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { DiagnosticSeverity } from 'vscode-languageserver-types';
2+
3+
import ApilintCodes from '../../../codes.ts';
4+
import { LinterMeta } from '../../../../apidom-language-types.ts';
5+
import { A2A1 } from '../../target-specs.ts';
6+
7+
const allowedFieldsLint: LinterMeta = {
8+
code: ApilintCodes.NOT_ALLOWED_FIELDS,
9+
source: 'apilint',
10+
message: 'Object includes not allowed fields',
11+
severity: DiagnosticSeverity.Error,
12+
linterFunction: 'allowedFields',
13+
linterParams: [['schemes']],
14+
marker: 'key',
15+
targetSpecs: A2A1,
16+
};
17+
18+
export default allowedFieldsLint;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import allowedFieldsLint from './allowed-fields.ts';
2+
3+
const lints = [allowedFieldsLint];
4+
5+
export default lints;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { FormatMeta } from '../../../apidom-language-types.ts';
2+
import lint from './lint/index.ts';
3+
import completion from './completion.ts';
4+
import documentation from './documentation.ts';
5+
6+
const meta: FormatMeta = {
7+
lint,
8+
completion,
9+
documentation,
10+
};
11+
12+
export default meta;

packages/apidom-ls/test/a2a.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ const agentCardDeviceCodeMissingScopes = fs
4444
)
4545
.toString();
4646

47+
const agentCardSecurityRequirementNotAllowedFields = fs
48+
.readFileSync(
49+
path.join(
50+
__dirname,
51+
'fixtures',
52+
'a2a',
53+
'agent-card-security-requirement-not-allowed-fields.json',
54+
),
55+
)
56+
.toString();
57+
4758
describe('apidom-ls-a2a', function () {
4859
const context: LanguageServiceContext = {
4960
metadata: metadata(),
@@ -359,6 +370,35 @@ describe('apidom-ls-a2a', function () {
359370
assert.deepEqual(result, expected);
360371
});
361372

373+
it('reports not-allowed fields on SecurityRequirement', async function () {
374+
this.timeout(10000);
375+
376+
const validationContext: ValidationContext = {
377+
comments: DiagnosticSeverity.Error,
378+
maxNumberOfProblems: 100,
379+
relatedInformation: false,
380+
};
381+
382+
const doc = TextDocument.create(
383+
'foo://bar/security-requirement-not-allowed-fields.json',
384+
'json',
385+
0,
386+
agentCardSecurityRequirementNotAllowedFields,
387+
);
388+
389+
const result = await languageService.doValidation(doc, validationContext);
390+
const expected: Diagnostic[] = [
391+
{
392+
range: { start: { line: 43, character: 4 }, end: { line: 48, character: 5 } },
393+
message: 'Object includes not allowed fields',
394+
severity: 1,
395+
code: 15000,
396+
source: 'apilint',
397+
},
398+
];
399+
assert.deepEqual(result, expected);
400+
});
401+
362402
it('reports missing scopes on DeviceCodeOAuthFlow', async function () {
363403
this.timeout(10000);
364404

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "Planner Agent",
3+
"description": "Breaks down a request into actionable tasks.",
4+
"version": "1.0.0",
5+
"iconUrl": "https://agent.example.com/icon.png",
6+
"documentationUrl": "https://agent.example.com/docs",
7+
"provider": {
8+
"organization": "Example Co.",
9+
"url": "https://example.com/"
10+
},
11+
"capabilities": {
12+
"streaming": true,
13+
"pushNotifications": true,
14+
"extendedAgentCard": false
15+
},
16+
"supportedInterfaces": [
17+
{
18+
"url": "https://agent.example.com/a2a/v1",
19+
"protocolBinding": "JSONRPC",
20+
"protocolVersion": "1.0"
21+
}
22+
],
23+
"defaultInputModes": ["text", "text/plain"],
24+
"defaultOutputModes": ["text", "text/plain"],
25+
"skills": [
26+
{
27+
"id": "planner",
28+
"name": "Task Planner",
29+
"description": "Plans tasks based on user goals.",
30+
"tags": ["planner"],
31+
"examples": ["Plan a business trip"]
32+
}
33+
],
34+
"securitySchemes": {
35+
"bearer": {
36+
"httpAuthSecurityScheme": {
37+
"description": "Bearer token authentication.",
38+
"scheme": "bearer",
39+
"bearerFormat": "JWT"
40+
}
41+
}
42+
},
43+
"securityRequirements": [
44+
{
45+
"schemes": {
46+
"bearer": []
47+
},
48+
"invalidField": "not-allowed"
49+
}
50+
]
51+
}

0 commit comments

Comments
 (0)