Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: regression on execution ordering #157

Merged
merged 2 commits into from
Nov 2, 2024
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
14 changes: 7 additions & 7 deletions @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.6.1",
"version": "1.7.0",
"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 Expand Up @@ -63,15 +63,15 @@
"astro": "^4.0.0"
},
"devDependencies": {
"@types/node": "^22.7.4",
"astro": "^4.15.11",
"@types/node": "^22.8.6",
"astro": "^4.16.8",
"get-tsconfig": "^4.8.1",
"rollup": "^4.24.0",
"rollup": "^4.24.3",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-esbuild": "^6.1.1",
"typescript": "^5.6.2",
"vite": "^5.4.8",
"vitest": "^2.1.2"
"typescript": "^5.6.3",
"vite": "^5.4.10",
"vitest": "^2.1.4"
},
"repository": {
"type": "git",
Expand Down
26 changes: 16 additions & 10 deletions @kindspells/astro-shield/src/core.mts
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ export const getViteMiddlewarePlugin = (
}
}

const getAstroBuildDone = (
export const getAstroBuildDone = (
state: IntegrationState,
sri: Required<SRIOptions>,
securityHeaders: SecurityHeadersOptions | undefined,
Expand Down Expand Up @@ -1042,15 +1042,21 @@ export const getAstroConfigSetup = (
})
}

updateConfig({
integrations: [
{
name: '@kindspells/astro-shield-post-config-setup',
hooks: {
'astro:build:done': getAstroBuildDone(state, sri, securityHeaders),
if (state.delayTransform) {
updateConfig({
integrations: [
{
name: '@kindspells/astro-shield-post-config-setup',
hooks: {
'astro:build:done': getAstroBuildDone(
state,
sri,
securityHeaders,
),
},
},
},
],
})
],
})
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"license": "MIT",
"dependencies": {
"@astrojs/node": "^8.3.4",
"astro": "^4.15.11"
"astro": "^4.16.8"
},
"devDependencies": {
"@kindspells/astro-shield": "workspace:*"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"license": "MIT",
"dependencies": {
"@astrojs/node": "^8.3.4",
"astro": "^4.15.11"
"astro": "^4.16.8"
},
"devDependencies": {
"@kindspells/astro-shield": "workspace:*"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"license": "MIT",
"dependencies": {
"@astrojs/node": "^8.3.4",
"astro": "^4.15.11"
"astro": "^4.16.8"
},
"devDependencies": {
"@kindspells/astro-shield": "workspace:*"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"license": "MIT",
"dependencies": {
"@astrojs/node": "^8.3.4",
"astro": "^4.15.11"
"astro": "^4.16.8"
},
"devDependencies": {
"@kindspells/astro-shield": "workspace:*"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"license": "MIT",
"dependencies": {
"astro": "^4.15.11"
"astro": "^4.16.8"
},
"devDependencies": {
"@kindspells/astro-shield": "workspace:*"
Expand Down
18 changes: 15 additions & 3 deletions @kindspells/astro-shield/src/main.mts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import type { AstroIntegration } from 'astro'

import { getAstroConfigSetup } from '#as/core'
import { getAstroBuildDone, getAstroConfigSetup } from '#as/core'
import type { IntegrationState, ShieldOptions, SRIOptions } from './types.mts'

const logWarn = (msg: string): void =>
Expand All @@ -15,10 +15,10 @@ const logWarn = (msg: string): void =>
// Integration
// -----------------------------------------------------------------------------
export const shield = ({
delayTransform,
securityHeaders,
sri,
}: ShieldOptions): AstroIntegration => {
// We need to merge the deprecated options into the new object
const _sri = {
enableMiddleware: sri?.enableMiddleware ?? false,
enableStatic: sri?.enableStatic ?? true,
Expand All @@ -35,12 +35,24 @@ export const shield = ({
logWarn('`sri.hashesModule` is ignored when `sri.enableStatic` is `false`')
}

const state: IntegrationState = { config: {} }
const _delayTransform =
delayTransform ??
securityHeaders?.enableOnStaticPages?.provider === 'vercel'

const state: IntegrationState = {
delayTransform: _delayTransform,
config: {},
}

return {
name: '@kindspells/astro-shield',
hooks: {
'astro:config:setup': getAstroConfigSetup(state, _sri, securityHeaders),
...(_delayTransform
? undefined
: {
'astro:build:done': getAstroBuildDone(state, _sri, securityHeaders),
}),
},
} satisfies AstroIntegration
}
Expand Down
37 changes: 29 additions & 8 deletions @kindspells/astro-shield/src/tests/main.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,33 @@ import { describe, expect, it } from 'vitest'
import defaultIntegrationExport, { shield } from '../main.mts'

describe('sriCSP', () => {
it('is exported as default', () => {
expect(defaultIntegrationExport).toBe(shield)
expect(shield).toBeInstanceOf(Function)
})
const defaultIntegrationKeys = [
'astro:build:done',
'astro:config:setup',
] as Readonly<['astro:build:done', 'astro:config:setup']>

const checkIntegration = (
integration: AstroIntegration,
keys: (keyof AstroIntegration['hooks'])[] = ['astro:config:setup'] as const,
keys: Readonly<
(keyof AstroIntegration['hooks'])[]
> = defaultIntegrationKeys,
) => {
expect(Object.keys(integration).sort()).toEqual(['hooks', 'name'])
expect(integration.name).toBe('@kindspells/astro-shield')

const sortedKeys = keys.sort()
const sortedKeys = keys.slice().sort() // TODO: use toSorted when widely available
expect(Object.keys(integration.hooks).sort()).toEqual(sortedKeys)
for (const key of sortedKeys) {
expect(integration.hooks[key]).toBeTruthy()
expect(integration.hooks[key]).toBeInstanceOf(Function)
}
}

it('is exported as default', () => {
expect(defaultIntegrationExport).toBe(shield)
expect(shield).toBeInstanceOf(Function)
})

it('returns a valid AstroIntegration object for default config', () => {
const integration = shield({})
checkIntegration(integration)
Expand All @@ -44,12 +51,12 @@ describe('sriCSP', () => {
const integration = shield({ sri: { enableStatic: false } })

// NOTE: it is too much work to verify that those hooks will do nothing
checkIntegration(integration, ['astro:config:setup'])
checkIntegration(integration, defaultIntegrationKeys)
})

it('returns hooks for static & dynamic content when we enable middleware', () => {
const integration = shield({ sri: { enableMiddleware: true } })
checkIntegration(integration, ['astro:config:setup'])
checkIntegration(integration, defaultIntegrationKeys)
})

it('returns hooks only for dynamic content when we enable middleware and disable static sri', () => {
Expand All @@ -59,6 +66,20 @@ describe('sriCSP', () => {
enableMiddleware: true,
},
})
checkIntegration(integration, defaultIntegrationKeys)
})

it('removes build:done from base config when delayTransform=true', () => {
const integration = shield({
delayTransform: true,
})
checkIntegration(integration, ['astro:config:setup'])
})

it('keeps build:done in base config when delayTransform=false', () => {
const integration = shield({
delayTransform: false,
})
checkIntegration(integration, ['astro:build:done', 'astro:config:setup'])
})
})
19 changes: 18 additions & 1 deletion @kindspells/astro-shield/src/types.mts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,20 @@ export type SecurityHeadersOptions = {
}

export type ShieldOptions = {
/**
* When set to `true`, the transformation of static pages will be delayed to
* be executed as late as possible in the build process. This might be
* necessary in case you are using many integrations that transform the HTML
* output.
*
* If not set and any of the following conditions are met, then this option
* will be automatically set to `true`:
* - securityHeaders.enableOnStaticPages is set to `{ provider: 'vercel' }`
*
* Defaults to `false`.
*/
delayTransform?: boolean

/**
* Options related to Subresource Integrity (SRI).
*/
Expand Down Expand Up @@ -176,4 +190,7 @@ export type HashesCollection = {
perResourceSriHashes: MiddlewareHashes
}

export type IntegrationState = { config: Partial<AstroConfig> }
export type IntegrationState = {
delayTransform: boolean
config: Partial<AstroConfig>
}
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.3/schema.json",
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": { "enabled": true },
"files": {
"include": ["*.json", "*.js", "*.mjs", "*.mts", "*.d.ts"],
Expand Down
12 changes: 8 additions & 4 deletions docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export default defineConfig({
trailingSlash: 'always',
image: { service: passthroughImageService() },
integrations: [
shield({}),
starlight({
title: 'Astro-Shield Docs',
defaultLocale: 'root',
Expand Down Expand Up @@ -66,7 +65,7 @@ export default defineConfig({
{
label: 'Subresource Integrity',
autogenerate: {
directory: 'guides/subresource-integrity'
directory: 'guides/subresource-integrity',
},
},
{
Expand All @@ -78,7 +77,7 @@ export default defineConfig({
ru: 'Заголовки безопасности',
},
autogenerate: {
directory: 'guides/security-headers'
directory: 'guides/security-headers',
},
},
{
Expand Down Expand Up @@ -141,7 +140,7 @@ export default defineConfig({
ca: 'Contribució',
es: 'Contribución',
hi: 'योगदान',
ru: 'Внести свой вклад'
ru: 'Внести свой вклад',
},
link: 'https://github.com/kindspells/astro-shield/blob/main/CONTRIBUTING.md',
},
Expand All @@ -163,5 +162,10 @@ export default defineConfig({
baseUrl: 'https://github.com/kindspells/astro-shield/edit/main/docs/',
},
}),
shield({ sri: { enableStatic: true } }),
],
build: {
format: 'directory',
inlineStylesheets: 'never',
},
})
10 changes: 5 additions & 5 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
"dependencies": {
"astro-sst": "^2.43.5",
"sharp": "0.33.5",
"sst": "^3.1.67"
"sst": "^3.2.73"
},
"devDependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/starlight": "^0.28.2",
"@astrojs/ts-plugin": "^1.10.2",
"@astrojs/starlight": "^0.28.5",
"@astrojs/ts-plugin": "^1.10.4",
"@kindspells/astro-shield": "workspace:^",
"astro": "^4.15.11",
"typescript": "^5.6.2"
"astro": "^4.16.8",
"typescript": "^5.6.3"
}
}
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
}
],
"devDependencies": {
"@biomejs/biome": "^1.9.3",
"@moonrepo/cli": "^1.28.3",
"@vitest/coverage-v8": "^2.1.2",
"publint": "^0.2.11",
"vitest": "^2.1.2"
"@biomejs/biome": "^1.9.4",
"@moonrepo/cli": "^1.29.3",
"@vitest/coverage-v8": "^2.1.4",
"publint": "^0.2.12",
"vitest": "^2.1.4"
},
"engines": {
"node": ">= 22.9.0"
Expand Down
Loading