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
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,72 @@ REQUIRED must have required property 'format'
6 | ],]
`;

exports[`headers > should throw on additional property in headers 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
ADDTIONAL PROPERTY must NOT have additional properties

33 | "x-custom-header": {
34 | "style": "exists",
> 35 | "foo": "bar"
| ^^^^^ 😲 foo is not expected to be here!
36 | }
37 | }
38 | }]
`;

exports[`headers > should throw on invalid pattern format 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
FORMAT must match format "regexPattern"

33 | "x-custom-header": {
34 | "style": "regex",
> 35 | "pattern": "/^Bearer .+/"
| ^^^^^^^^^^^^^^ 👈🏽 format must match format "regexPattern"
36 | }
37 | }
38 | }]
`;

exports[`headers > should throw on invalid style value 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
ENUM must be equal to one of the allowed values
(exists, missing, regex)

32 | "headers": {
33 | "x-custom-header": {
> 34 | "style": "invalid"
| ^^^^^^^^^ 👈🏽 Unexpected value, should be equal to one of the allowed values
35 | }
36 | }
37 | }]
`;

exports[`headers > should throw on missing style property 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
REQUIRED must have required property 'style'

31 | "bundler_version": "1.6.0",
32 | "headers": {
> 33 | "x-custom-header": {
| ^ ☹️ style is missing here!
34 | "pattern": "^Bearer .+"
35 | }
36 | }]
`;

exports[`headers > should throw when style is regex but pattern is missing 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
REQUIRED must have required property 'pattern'

31 | "bundler_version": "1.6.0",
32 | "headers": {
> 33 | "x-custom-header": {
| ^ ☹️ pattern is missing here!
34 | "style": "regex"
35 | }
36 | }]
`;

exports[`import map URL > should throw on wrong type 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
TYPE must be string
Expand Down Expand Up @@ -159,6 +225,72 @@ REQUIRED must have required property 'pattern'
12 | "generator": "@netlify/[email protected]"]
`;

exports[`route headers > should throw on additional property in headers 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
ADDTIONAL PROPERTY must NOT have additional properties

15 | "x-custom-header": {
16 | "style": "exists",
> 17 | "foo": "bar"
| ^^^^^ 😲 foo is not expected to be here!
18 | }
19 | }
20 | }]
`;

exports[`route headers > should throw on invalid pattern format 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
FORMAT must match format "regexPattern"

15 | "x-custom-header": {
16 | "style": "regex",
> 17 | "pattern": "/^Bearer .+/"
| ^^^^^^^^^^^^^^ 👈🏽 format must match format "regexPattern"
18 | }
19 | }
20 | }]
`;

exports[`route headers > should throw on invalid style value 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
ENUM must be equal to one of the allowed values
(exists, missing, regex)

14 | "headers": {
15 | "x-custom-header": {
> 16 | "style": "invalid"
| ^^^^^^^^^ 👈🏽 Unexpected value, should be equal to one of the allowed values
17 | }
18 | }
19 | }]
`;

exports[`route headers > should throw on missing style property 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
REQUIRED must have required property 'style'

13 | "generator": "@netlify/[email protected]",
14 | "headers": {
> 15 | "x-custom-header": {
| ^ ☹️ style is missing here!
16 | "pattern": "^Bearer .+$"
17 | }
18 | }]
`;

exports[`route headers > should throw when style is regex but pattern is missing 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
REQUIRED must have required property 'pattern'

13 | "generator": "@netlify/[email protected]",
14 | "headers": {
> 15 | "x-custom-header": {
| ^ ☹️ pattern is missing here!
16 | "style": "regex"
17 | }
18 | }]
`;

exports[`should show multiple errors 1`] = `
[ManifestValidationError: Validation of Edge Functions manifest failed
ADDTIONAL PROPERTY must NOT have additional properties
Expand Down
111 changes: 111 additions & 0 deletions packages/edge-bundler/node/validation/manifest/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,114 @@ describe('import map URL', () => {
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot()
})
})

describe('route headers', () => {
test('should accept valid headers with exists style', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'exists',
},
}

expect(() => validateManifest(manifest)).not.toThrowError()
})

test('should accept valid headers with missing style', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'missing',
},
}

expect(() => validateManifest(manifest)).not.toThrowError()
})

test('should accept valid headers with regex style and pattern', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'regex',
pattern: '^Bearer .+$',
},
}

expect(() => validateManifest(manifest)).not.toThrowError()
})

test('should throw on missing style property', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
pattern: '^Bearer .+$',
},
}

expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot()
})

test('should throw on invalid style value', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'invalid',
},
}

expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot()
})

test('should throw when style is regex but pattern is missing', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'regex',
},
}

expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot()
})

test('should throw on invalid pattern format', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'regex',
pattern: '/^Bearer .+/',
},
}

expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot()
})

test('should throw on additional property in headers', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-custom-header': {
style: 'exists',
foo: 'bar',
},
}

expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot()
})

test('should accept multiple headers with different styles', () => {
const manifest = getBaseManifest()
manifest.routes[0].headers = {
'x-exists-header': {
style: 'exists',
},
'x-missing-header': {
style: 'missing',
},
authorization: {
style: 'regex',
pattern: '^Bearer [a-zA-Z0-9]+$',
},
}

expect(() => validateManifest(manifest)).not.toThrowError()
})
})
31 changes: 31 additions & 0 deletions packages/edge-bundler/node/validation/manifest/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,36 @@ const excludedPatternsSchema = {
},
}

const headersSchema = {
type: 'object',
patternProperties: {
'.*': {
type: 'object',
required: ['style'],
properties: {
pattern: {
type: 'string',
format: 'regexPattern',
},
style: {
type: 'string',
enum: ['exists', 'missing', 'regex'],
},
},
additionalProperties: false,
if: {
properties: {
style: { const: 'regex' },
},
},
then: {
required: ['pattern'],
},
},
},
additionalProperties: false,
}

const routesSchema = {
type: 'object',
required: ['function', 'pattern'],
Expand All @@ -36,6 +66,7 @@ const routesSchema = {
type: 'array',
items: { type: 'string', enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'] },
},
headers: headersSchema,
},
additionalProperties: false,
}
Expand Down
Loading