Skip to content

Commit

Permalink
test: increase coverage
Browse files Browse the repository at this point in the history
Signed-off-by: Andres Correa Casablanca <[email protected]>
  • Loading branch information
castarco committed Sep 19, 2024
1 parent 297bf1d commit 0329906
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 17 deletions.
6 changes: 6 additions & 0 deletions @kindspells/astro-shield/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,9 @@ tasks:
- 'coverage-unit/**/*'
deps:
- '~:build'
test:
deps:
- '~:test.unit.cov'
- '~:test.e2e'
options:
runInCI: false
2 changes: 1 addition & 1 deletion @kindspells/astro-shield/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kindspells/astro-shield",
"version": "1.5.2",
"version": "1.5.3",
"description": "Astro integration to enhance your website's security with SubResource Integrity hashes, Content-Security-Policy headers, and other techniques.",
"private": false,
"type": "module",
Expand Down
8 changes: 3 additions & 5 deletions @kindspells/astro-shield/src/core.mts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
StrictShieldOptions,
} from './types.mts'
import { patchNetlifyHeadersConfig } from './netlify.mts'
import { exhaustiveGuard } from './utils.mts'

export type HashesModule = {
[k in keyof HashesCollection]: HashesCollection[k] extends Set<string>
Expand All @@ -33,10 +34,6 @@ export type HashesModule = {
: Record<'scripts' | 'styles', Record<string, string>>
}

const exhaustiveGuard = (_v: never, caseName: string): void => {
throw new Error(`Unknown ${caseName}: ${_v}`)
}

export const generateSRIHash = (
data: string | ArrayBuffer | Buffer,
): string => {
Expand Down Expand Up @@ -964,7 +961,8 @@ export const onRequest = await (async () => {
`
}

const getViteMiddlewarePlugin = (
/** @internal */
export const getViteMiddlewarePlugin = (
logger: Logger,
sri: Required<SRIOptions>,
securityHeaders: SecurityHeadersOptions | undefined,
Expand Down
2 changes: 2 additions & 0 deletions @kindspells/astro-shield/src/fs.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { resolve } from 'node:path'

import type { HashesCollection, Logger, SRIOptions } from './types.mts'

/** @internal */
export const doesFileExist = async (path: string): Promise<boolean> => {
try {
await stat(path)
Expand All @@ -21,6 +22,7 @@ export const doesFileExist = async (path: string): Promise<boolean> => {
}
}

/** @internal */
export const scanDirectory = async (
logger: Logger,
currentPath: string,
Expand Down
2 changes: 1 addition & 1 deletion @kindspells/astro-shield/src/main.mts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const shield = ({
} satisfies Required<SRIOptions>

if (_sri.hashesModule && _sri.enableStatic === false) {
logWarn('`sriHashesModule` is ignored when `enableStatic_SRI` is `false`')
logWarn('`sri.hashesModule` is ignored when `sri.enableStatic` is `false`')
}

return {
Expand Down
14 changes: 8 additions & 6 deletions @kindspells/astro-shield/src/netlify.mts
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ const processPathLine = (
): void => {
let match: RegExpMatchArray | null = null

// biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
// biome-ignore lint/suspicious/noAssignInExpressions: best way to do it
if ((match = commentRegex.exec(line))) {
pushEntry(match, lineNum, line, pushComment, ctx)
}
// biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
// biome-ignore lint/suspicious/noAssignInExpressions: best way to do it
else if ((match = headerRegex.exec(line))) {
pushEntry(match, lineNum, line, pushHeader, ctx)
} else if (!spacesRegex.test(line)) {
Expand Down Expand Up @@ -211,7 +211,8 @@ const compareConfigEntries = (
: 0
}

const comparePathEntries = (
/** @internal */
export const comparePathEntries = (
a: HeaderEntry | CommentEntry,
b: HeaderEntry | CommentEntry,
): -1 | 0 | 1 => {
Expand All @@ -229,7 +230,8 @@ const comparePathEntries = (
: 0
}

const comparePathEntriesSimplified = (
/** @internal */
export const comparePathEntriesSimplified = (
a: HeaderEntry | CommentEntry,
b: HeaderEntry | CommentEntry,
): -1 | 0 | 1 => {
Expand Down Expand Up @@ -344,11 +346,11 @@ const mergeNetlifyPathHeaders = (
}
}
for (; baseIndex < base.length; baseIndex += 1) {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
// biome-ignore lint/style/noNonNullAssertion: guaranteed to exist
merged.push(base[baseIndex]!)
}
for (; patchIndex < patch.length; patchIndex += 1) {
// biome-ignore lint/style/noNonNullAssertion: <explanation>
// biome-ignore lint/style/noNonNullAssertion: guaranteed to exist
merged.push(patch[patchIndex]!)
}

Expand Down
66 changes: 66 additions & 0 deletions @kindspells/astro-shield/src/tests/core.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
sriHashesEqual,
updateDynamicPageSriHashes,
updateStaticPageSriHashes,
getAstroConfigSetup,
getViteMiddlewarePlugin,
} from '../core.mts'
import { doesFileExist } from '../fs.mts'

Expand Down Expand Up @@ -2029,3 +2031,67 @@ describe('getCSPMiddlewareHandler', () => {
</html>`)
})
})

describe('getViteMiddlewarePlugin', () => {
it('returns a vite middleware plugin object', async () => {
const plugin = getViteMiddlewarePlugin(
console,
{
enableStatic: false,
enableMiddleware: false,
allowInlineScripts: false,
allowInlineStyles: false,
hashesModule: '/path/to/hashes.mjs',
scriptsAllowListUrls: [],
stylesAllowListUrls: [],
},
{},
'/path/to/site/',
)

expect(plugin).toHaveProperty('name')
expect(plugin).toHaveProperty('resolveId')
expect(plugin).toHaveProperty('load')

expect(plugin.name).toBe('vite-plugin-astro-shield')

assert(typeof plugin.resolveId === 'function')
expect(
(plugin.resolveId as unknown as (a: string) => string | undefined)(
'virtual:@kindspells/astro-shield/middleware',
),
).toStrictEqual('\u0000virtual:@kindspells/astro-shield/middleware')
expect(
(plugin.resolveId as unknown as (a: string) => string | undefined)(
'virtual:@something/else/middleware',
),
).toStrictEqual(undefined)

assert(typeof plugin.load === 'function')
// We won't check the "happy path" because it triggers too many side effects
expect(
await (plugin.load as (a: string) => Promise<string | undefined>)(
'virtual:@something/else/middleware',
),
).toStrictEqual(undefined)
})
})

describe('getAstroConfigSetup', () => {
// We don't test anything else because it would trigger too many side effects
it('returns an "astro:config:setup" hook function', () => {
const setup = getAstroConfigSetup(
{
enableStatic: false,
enableMiddleware: false,
allowInlineScripts: false,
allowInlineStyles: false,
hashesModule: '/path/to/hashes.mjs',
scriptsAllowListUrls: [],
stylesAllowListUrls: [],
},
{},
)
expect(typeof setup).toBe('function')
})
})
100 changes: 100 additions & 0 deletions @kindspells/astro-shield/src/tests/netlify.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { describe, expect, it } from 'vitest'
import type { NetlifyHeadersRawConfig } from '../netlify.mts'
import {
buildNetlifyHeadersConfig,
comparePathEntries,
comparePathEntriesSimplified,
mergeNetlifyHeadersConfig,
parseNetlifyHeadersConfig,
readNetlifyHeadersFile,
Expand All @@ -31,6 +33,104 @@ const testEntries = [
},
] satisfies NetlifyHeadersRawConfig['entries']

describe('comparePathEntries', () => {
it.each([
[{ comment: 'Comment A' }, { comment: 'Comment B' }],
[
{ comment: 'Comment A' },
{ headerName: 'X-Frame-Options', value: 'DENY' },
],
[
{ headerName: 'X-Frame-Options', value: 'DENY' },
{ comment: 'Comment A' },
],
] as const)('returns 0 if there is any comment', (entryA, entryB) => {
expect(comparePathEntries(entryA, entryB)).toBe(0)
})

it.each([
[
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
0,
],
[
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
{ headerName: 'X-Frame-Options', value: 'DENY' },
-1,
],
[
{ headerName: 'X-Frame-Options', value: 'DENY' },
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
1,
],
[
{ headerName: 'X-Frame-Options', value: 'ALLOW' },
{ headerName: 'X-Frame-Options', value: 'DENY' },
-1,
],
[
{ headerName: 'X-Frame-Options', value: 'DENY' },
{ headerName: 'X-Frame-Options', value: 'ALLOW' },
1,
],
] as const)(
'compares headers by name and value',
(entryA, entryB, result) => {
expect(comparePathEntries(entryA, entryB)).toBe(result)
},
)
})

describe('comparePathEntriesSimplified', () => {
it.each([
[{ comment: 'Comment A' }, { comment: 'Comment B' }],
[
{ comment: 'Comment A' },
{ headerName: 'X-Frame-Options', value: 'DENY' },
],
[
{ headerName: 'X-Frame-Options', value: 'DENY' },
{ comment: 'Comment A' },
],
] as const)('returns 0 if there is any comment', (entryA, entryB) => {
expect(comparePathEntriesSimplified(entryA, entryB)).toBe(0)
})

it.each([
[
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
0,
],
[
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
{ headerName: 'X-Frame-Options', value: 'DENY' },
-1,
],
[
{ headerName: 'X-Frame-Options', value: 'DENY' },
{ headerName: 'Authorization', value: 'Bearer 0123456789abcdef' },
1,
],
[
{ headerName: 'X-Frame-Options', value: 'ALLOW' },
{ headerName: 'X-Frame-Options', value: 'DENY' },
0,
],
[
{ headerName: 'X-Frame-Options', value: 'DENY' },
{ headerName: 'X-Frame-Options', value: 'ALLOW' },
0,
],
] as const)(
'compares headers by name and value',
(entryA, entryB, result) => {
expect(comparePathEntriesSimplified(entryA, entryB)).toBe(result)
},
)
})

describe('parseNetlifyHeadersConfig', () => {
it('parses a valid config (tabs)', () => {
const config = `# This is a test config file
Expand Down
11 changes: 11 additions & 0 deletions @kindspells/astro-shield/src/tests/utils.test.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { describe, expect, it } from 'vitest'

import { exhaustiveGuard } from '../utils.mts'

describe('exhaustiveGuard', () => {
it('does something', () => {
expect(() => exhaustiveGuard('x' as never, 'something')).toThrowError(
'Unknown something: x',
)
})
})
4 changes: 4 additions & 0 deletions @kindspells/astro-shield/src/utils.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @internal */
export const exhaustiveGuard = (_v: never, caseName: string): void => {
throw new Error(`Unknown ${caseName}: ${_v}`)
}
8 changes: 4 additions & 4 deletions @kindspells/astro-shield/vitest.config.unit.mts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ export default defineConfig({
'coverage-unit/**/*',
],
thresholds: {
statements: 75.0, // TODO: 77.0,
branches: 78.0,
functions: 80.0, // TODO: 87.0,
lines: 75.0, // TODO: 77.0,
statements: 78.0,
branches: 80.0,
functions: 88.0,
lines: 78.0,
},
reportsDirectory: 'coverage-unit',
},
Expand Down

0 comments on commit 0329906

Please sign in to comment.