Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"@heroui/theme": "^2.4.26",
"@next/eslint-plugin-next": "15.5.28",
"@octokit/webhooks-types": "^7.6.1",
"@scalar/openapi-parser": "^0.29.16",
"@swc/core": "^1.16.18",
"@swc/jest": "^0.2.39",
"@types/dotenv": "^6.1.1",
Expand Down Expand Up @@ -163,7 +164,7 @@
"^.+\\.(js|ts)$": "@swc/jest"
},
"transformIgnorePatterns": [
"/node_modules/(?!\\.pnpm/|ai/|@ai-sdk/|@workflow/|jose/)"
"/node_modules/(?!\\.pnpm/|ai/|@ai-sdk/|@workflow/|jose/|@scalar/)"
],
"setupFilesAfterEnv": [
"<rootDir>/jestSetup.ts"
Expand Down
129 changes: 129 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,43 @@ function renderCallbackPage(options: {
* name: state
* schema:
* type: string
* responses:
* '200':
* description: HTML page confirming the connection; posts the result to the opener window
* content:
* text/html:
* schema:
* type: string
* '400':
* description: HTML page describing why the connection failed
* content:
* text/html:
* schema:
* type: string
* '404':
* description: HTML page shown when the connection no longer exists
* content:
* text/html:
* schema:
* type: string
* '409':
* description: HTML page shown when the connection state conflicts with the callback
* content:
* text/html:
* schema:
* type: string
* '410':
* description: HTML page shown when the connection attempt expired
* content:
* text/html:
* schema:
* type: string
* '422':
* description: HTML page shown when the provider response could not be processed
* content:
* text/html:
* schema:
* type: string
*/
const getHandler = async (req: NextRequest, { params }: { params: Promise<{ slug: string }> }) => {
const { slug } = await params;
Expand Down
48 changes: 24 additions & 24 deletions src/app/api/v2/builds/[uuid]/services/[name]/deploy-jobs/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,30 +58,30 @@ import { getDeploymentJobs } from 'server/lib/kubernetes/getDeploymentJobs';
* application/json:
* schema:
* $ref: '#/components/schemas/GetDeployLogsSuccessResponse'
* '400':
* description: Invalid parameters
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '404':
* description: Environment or service not found
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '502':
* description: Failed to communicate with Kubernetes
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '500':
* description: Internal server error
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '400':
* description: Invalid parameters
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '404':
* description: Environment or service not found
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '502':
* description: Failed to communicate with Kubernetes
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
* '500':
* description: Internal server error
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ApiErrorResponse'
*/
const getHandler = async (
req: NextRequest,
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/v2/environments/[uuid]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ import {
* '400': { description: Invalid request body (invalid_body). }
* '404': { description: Environment not found. }
* '409': { description: Teardown already owns the environment (env_tearing_down). }
* '422': { description: Invalid override, or autoTrack on an immutable source (auto_track_pinned_source). }
* '422': { description: 'Invalid override, or autoTrack on an immutable source (auto_track_pinned_source).' }
* delete:
* summary: Destroy an environment
* security:
Expand Down
4 changes: 2 additions & 2 deletions src/app/api/v2/environments/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ import {
* application/json:
* schema: { $ref: '#/components/schemas/EnvironmentCreateSuccessResponse' }
* '400': { description: Invalid body or ambiguous environment (env_ambiguous). }
* '403': { description: Missing scope, repository not allowed for token, or api_environments disabled. }
* '403': { description: 'Missing scope, repository not allowed for token, or api_environments disabled.' }
* '404': { description: Repository not onboarded (repo_not_onboarded). }
* '409': { description: Vanity name already taken (name_conflict). }
* '422': { description: Invalid config/override, or autoTrack with an immutable sha (auto_track_pinned_source). }
* '422': { description: 'Invalid config/override, or autoTrack with an immutable sha (auto_track_pinned_source).' }
*/
const getHandler = createPrincipalApiHandler({ scope: 'env:read' }, async (req: NextRequest, principal) => {
const { searchParams } = req.nextUrl;
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/v2/me/tokens/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import { serializeUserToken, assertIssuanceEnabled, assertNoUnknownFields, TOKEN
* schema: { $ref: '#/components/schemas/PersonalApiTokenCreateSuccessResponse' }
* '400': { description: Invalid body / repository access / expiry. }
* '401': { description: Not authenticated. }
* '403': { description: Role not permitted, forbidden scope, or key issuance disabled (api_keys_disabled). }
* '403': { description: 'Role not permitted, forbidden scope, or key issuance disabled (api_keys_disabled).' }
*/
const getHandler = async (req: NextRequest) => {
ApiTokenService.assertManagementAllowed();
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/v2/tokens/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const parsePositiveIntegerParam = (value: string | null, name: string, fallback:
* application/json:
* schema: { $ref: '#/components/schemas/ServiceApiTokenCreateSuccessResponse' }
* '400': { description: Invalid body. }
* '403': { description: Requires the admin role, forbidden scope, or key issuance disabled (api_keys_disabled). }
* '403': { description: 'Requires the admin role, forbidden scope, or key issuance disabled (api_keys_disabled).' }
*/
const getHandler = async (req: NextRequest) => {
ApiTokenService.assertManagementAllowed();
Expand Down
10 changes: 10 additions & 0 deletions src/shared/openApiSpec.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1026,3 +1026,13 @@ describe('OpenAPI v2 agent session contract', () => {
});
});
});

describe('OpenAPI v2 spec validity', () => {
it('passes strict OpenAPI validation', async () => {
const { validate } = await import('@scalar/openapi-parser');
const result = await validate(swaggerSpec);
const errors = (result.errors ?? []).map((e: { message: string }) => e.message);
expect(errors).toEqual([]);
expect(result.valid).toBe(true);
});
});
Loading
Loading