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
2 changes: 1 addition & 1 deletion guidelines/skills/add-docs-links/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ For **edits or removals**: find the row by `path` and/or its `docs` key; update
- New ref for an existing repo: resolve SHA (e.g. commits API) or use a stable tag.

2. **Whitelist**
- `path` must match `patternflyOptions.urlWhitelist` in `src/options.defaults.ts`. See [reference.md — URL whitelist](reference.md#url-whitelist-allowed-domains). Use **https** only. Do not widen the whitelist in a catalog-only PR.
- `path` must match `whitelist.urls` in `src/options.defaults.ts`. See [reference.md — URL whitelist](reference.md#url-whitelist-allowed-domains). Use **https** only. Do not widen the whitelist in a catalog-only PR.

3. **Reachability**
- Response must be 2xx (e.g. `curl -sI -o /dev/null -w "%{http_code}" "<url>"`). If not, fix ref or path; do not add a dead link.
Expand Down
2 changes: 1 addition & 1 deletion guidelines/skills/add-docs-links/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Each object in `docs.<Key>[]`:

## URL whitelist (allowed domains)

Defined in `src/options.defaults.ts` → `patternflyOptions.urlWhitelist`. Used when validating/fetching paths.
Defined in `src/options.defaults.ts` → `whitelist.urls`. Used when validating/fetching paths.

- **Prefixes:** `https://patternfly.org`, `https://github.com/patternfly`, `https://raw.githubusercontent.com/patternfly`
- **`docs.json`:** use **https** only.
Expand Down
20 changes: 11 additions & 9 deletions src/__tests__/__snapshots__/options.defaults.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,6 @@ exports[`options defaults should return specific properties: defaults 1`] = `
"@patternfly/patternfly",
],
},
"urlWhitelist": [
"https://patternfly.org",
"https://github.com/patternfly",
"https://raw.githubusercontent.com/patternfly",
],
"urlWhitelistProtocols": [
"http",
"https",
],
},
"pluginHost": {
"gracePeriodMs": 2000,
Expand Down Expand Up @@ -141,6 +132,17 @@ exports[`options defaults should return specific properties: defaults 1`] = `
"toolModules": [],
"urlRegex": /\\^\\(https\\?:\\)\\\\/\\\\//i,
"version": "0.0.0",
"whitelist": {
"protocols": [
"http",
"https",
],
"urls": [
"https://patternfly.org",
"https://github.com/patternfly",
"https://raw.githubusercontent.com/patternfly",
],
},
"xhrFetch": {
"timeoutMs": 15000,
},
Expand Down
1 change: 0 additions & 1 deletion src/__tests__/options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,3 @@ describe('SET_OPTIONS', () => {
}
});
});

2 changes: 1 addition & 1 deletion src/options.context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
): GlobalOptions => {
const base = mergeObjects(DEFAULT_OPTIONS as GlobalOptions, options, { allowNullValues: false, allowUndefinedValues: false });

assertProtocol(base.patternflyOptions.urlWhitelist, base.patternflyOptions.urlWhitelistProtocols);
assertProtocol(base.whitelist.urls, base.whitelist.protocols);

const baseLogging = isPlainObject(base.logging) ? base.logging : DEFAULT_OPTIONS.logging;
const basePluginIsolation = PLUGIN_ISOLATION.includes(base.pluginIsolation) ? base.pluginIsolation : DEFAULT_OPTIONS.pluginIsolation;
Expand Down Expand Up @@ -219,7 +219,7 @@
callback: () => TReturn | Promise<TReturn>
) => {
// Avoid cloning toolModules
const originalToolModules = Array.isArray((options as any).toolModules) ? (options as any).toolModules : [];

Check warning on line 222 in src/options.context.ts

View workflow job for this annotation

GitHub Actions / Integration-checks (24.x)

Unexpected any. Specify a different type

Check warning on line 222 in src/options.context.ts

View workflow job for this annotation

GitHub Actions / Integration-checks (24.x)

Unexpected any. Specify a different type

Check warning on line 222 in src/options.context.ts

View workflow job for this annotation

GitHub Actions / Integration-checks (22.x)

Unexpected any. Specify a different type

Check warning on line 222 in src/options.context.ts

View workflow job for this annotation

GitHub Actions / Integration-checks (22.x)

Unexpected any. Specify a different type
const cloned = structuredClone({ ...(options as any), toolModules: [] as unknown[] });
const restoreOriginalToolModules = { ...cloned, toolModules: originalToolModules } as GlobalOptions;
const frozen = freezeObject(restoreOriginalToolModules);
Expand Down
55 changes: 38 additions & 17 deletions src/options.defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import { getNodeMajorVersion } from './options.helpers';
* registered with the server.
* @property urlRegex - Regular expression pattern for URL matching.
* @property version - Version of the package.
* @property whitelist - Central outbound-URL policy options.
* @property xhrFetch - XHR and Fetch options.
*/
interface DefaultOptions<TLogOptions = LoggingOptions> {
Expand Down Expand Up @@ -84,6 +85,7 @@ interface DefaultOptions<TLogOptions = LoggingOptions> {
toolModules: ToolModule | ToolModule[];
urlRegex: RegExp;
version: string;
whitelist: WhitelistOptions;
xhrFetch: XhrFetchOptions;
}

Expand Down Expand Up @@ -173,11 +175,6 @@ interface ModeOptions {
} | undefined;
}

/**
* A string that must start with a valid protocol.
*/
type WhitelistUrl = `${'http' | 'https'}://${string}`;

/**
* PatternFly-specific options.
*
Expand All @@ -192,8 +189,6 @@ type WhitelistUrl = `${'http' | 'https'}://${string}`;
* @property default.versionStrategy Strategy to use when multiple PatternFly versions are detected.
* - 'highest': Use the highest major version found.
* - 'lowest': Use the lowest major version found.
* @property {WhitelistUrl[]} urlWhitelist List of allowed URLs to fetch PatternFly resources from.
* @property urlWhitelistProtocols List of allowed URL protocols to validate against when fetching PatternFly resources.
*/
interface PatternFlyOptions {
availableResourceVersions: ('6.0.0')[];
Expand All @@ -205,9 +200,7 @@ interface PatternFlyOptions {
latestSchemasVersion: 'v6';
versionWhitelist: string[];
versionStrategy: 'highest' | 'lowest';
},
urlWhitelist: WhitelistUrl[];
urlWhitelistProtocols: string[];
}
}

/**
Expand Down Expand Up @@ -289,6 +282,26 @@ interface StatsSession extends StatsOptions {
channels: StatsChannels
}

/**
* A string that must start with a valid protocol.
*/
type WhitelistUrl = `${'http' | 'https'}://${string}`;

/**
* Central outbound-URL policy.
*
* @note Any code that fetches a remote URL; PatternFly docs,
* resource loaders; must validate against this list via
* `assertInputUrlWhiteListed`.
*
* @property urls Allowed URL prefixes (scheme + host [+ path]).
* @property protocols Allowed URL protocols.
*/
interface WhitelistOptions {
urls: WhitelistUrl[];
protocols: ('http' | 'https')[];
}

/**
* XHR and Fetch options.
*
Expand Down Expand Up @@ -437,6 +450,18 @@ const STATS_OPTIONS: StatsOptions = {
}
};

/**
* Central outbound-URL policy. Single source of truth on `DefaultOptions.whitelist`.
*/
const WHITELIST_OPTIONS: WhitelistOptions = {
urls: [
'https://patternfly.org',
'https://github.com/patternfly',
'https://raw.githubusercontent.com/patternfly'
],
protocols: ['http', 'https']
};

/**
* Default XHR and Fetch options.
*/
Expand Down Expand Up @@ -465,13 +490,7 @@ const PATTERNFLY_OPTIONS: PatternFlyOptions = {
'@patternfly/patternfly'
],
versionStrategy: 'highest'
},
urlWhitelist: [
'https://patternfly.org',
'https://github.com/patternfly',
'https://raw.githubusercontent.com/patternfly'
],
urlWhitelistProtocols: ['http', 'https']
}
};

/**
Expand Down Expand Up @@ -534,6 +553,7 @@ const DEFAULT_OPTIONS: DefaultOptions = {
separator: DEFAULT_SEPARATOR,
urlRegex: URL_REGEX,
version: (process.env.NODE_ENV === 'local' && '0.0.0') || packageJson.version,
whitelist: WHITELIST_OPTIONS,
xhrFetch: XHR_FETCH_OPTIONS
};

Expand All @@ -554,6 +574,7 @@ export {
type ServerInstanceOptions,
type StatsSession,
type ToolModule,
type WhitelistOptions,
type WhitelistUrl,
type XhrFetchOptions
};
2 changes: 1 addition & 1 deletion src/server.assertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function assertInputStringNumberEnumLike(
function assertInputUrlWhiteListed(
input: unknown,
whitelist: WhitelistUrl[],
{ allowedProtocols = DEFAULT_OPTIONS.patternflyOptions.urlWhitelistProtocols, inputDisplayName, message, urlDisplayMaxLength = 50 }: {
{ allowedProtocols = DEFAULT_OPTIONS.whitelist.protocols, inputDisplayName, message, urlDisplayMaxLength = 50 }: {
allowedProtocols?: string[]; inputDisplayName?: string; message?: string; urlDisplayMaxLength?: number
} = {}
): asserts input is string | string[] {
Expand Down
2 changes: 1 addition & 1 deletion src/tool.patternFlyDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const usePatternFlyDocsTool = (options = getOptions()): McpTool => {
if (options.mode !== 'test') {
assertInputUrlWhiteListed(
urlList,
options.patternflyOptions.urlWhitelist,
options.whitelist.urls,
{ inputDisplayName: 'urlList' }
);
}
Expand Down
Loading