From b8b67b574011074720b9f7d252b9ee2005b9a97b Mon Sep 17 00:00:00 2001 From: Gabriele Mambrini Date: Fri, 5 Nov 2021 09:52:50 +0100 Subject: [PATCH 1/5] Add allowed paths to backend.reading.allow Signed-off-by: Gabriele Mambrini --- .../src/reading/FetchUrlReader.test.ts | 7 +++++++ .../backend-common/src/reading/FetchUrlReader.ts | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/backend-common/src/reading/FetchUrlReader.test.ts b/packages/backend-common/src/reading/FetchUrlReader.test.ts index 124abb799c..9d6edee765 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.test.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.test.ts @@ -77,6 +77,10 @@ describe('FetchUrlReader', () => { { host: 'example.com:700' }, { host: '*.examples.org' }, { host: '*.examples.org:700' }, + { + host: 'foobar.org', + paths: ['/dir1/'], + }, ], }, }, @@ -106,6 +110,9 @@ describe('FetchUrlReader', () => { expect(predicate(new URL('https://examples.org:700/test'))).toBe(false); expect(predicate(new URL('https://a.examples.org:700/test'))).toBe(true); expect(predicate(new URL('https://a.b.examples.org:700/test'))).toBe(true); + expect(predicate(new URL('https://foobar.org/dir1/subpath'))).toBe(true); + expect(predicate(new URL('https://foobar.org/dir12'))).toBe(false); + expect(predicate(new URL('https://foobar.org/'))).toBe(false); }); describe('read', () => { diff --git a/packages/backend-common/src/reading/FetchUrlReader.ts b/packages/backend-common/src/reading/FetchUrlReader.ts index 732d3b9f59..1ae9677a85 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.ts @@ -24,6 +24,7 @@ import { SearchResponse, UrlReader, } from './types'; +import { normalize as normalizePath } from 'path'; /** * A UrlReader that does a plain fetch of the URL. @@ -39,18 +40,28 @@ export class FetchUrlReader implements UrlReader { * `host`: * Either full hostnames to match, or subdomain wildcard matchers with a leading `*`. * For example `example.com` and `*.example.com` are valid values, `prod.*.example.com` is not. + * + * `paths`: + * An optional list of paths which are allowed. If the list is omitted all paths are allowed. */ static factory: ReaderFactory = ({ config }) => { const predicates = config .getOptionalConfigArray('backend.reading.allow') ?.map(allowConfig => { + const paths = allowConfig.getOptionalStringArray('paths'); + const checkPath = paths + ? (url: URL) => { + const targetPath = normalizePath(url.pathname); + return paths.some(path => targetPath.startsWith(path)); + } + : (_url: URL) => true; const host = allowConfig.getString('host'); if (host.startsWith('*.')) { const suffix = host.slice(1); - return (url: URL) => url.host.endsWith(suffix); + return (url: URL) => url.host.endsWith(suffix) && checkPath(url); } - return (url: URL) => url.host === host; + return (url: URL) => url.host === host && checkPath(url); }) ?? []; const reader = new FetchUrlReader(); From bfc837a97b5cd16916ac241067df90e62a149479 Mon Sep 17 00:00:00 2001 From: Gabriele Mambrini Date: Fri, 5 Nov 2021 09:53:45 +0100 Subject: [PATCH 2/5] Update docs for allowed paths in backend.reading.allow Signed-off-by: Gabriele Mambrini --- docs/features/software-catalog/descriptor-format.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 7100e86ed0..57473ce4c7 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -144,7 +144,8 @@ spec: Note that to be able to read from targets that are outside of the normal integration points such as `github.com`, you'll need to explicitly allow it by -adding an entry in the `backend.reading.allow` list. For example: +adding an entry in the `backend.reading.allow` list. Paths can be specified to +further restrict targets For example: ```yml backend: @@ -153,6 +154,8 @@ backend: allow: - host: example.com - host: '*.examples.org' + - host: example.net + paths: ['/api/'] ``` ## Common to All Kinds: The Envelope From 1daada3a06f511ee31614822e7d00cd4f88fd0fe Mon Sep 17 00:00:00 2001 From: Gabriele Mambrini Date: Fri, 5 Nov 2021 10:00:17 +0100 Subject: [PATCH 3/5] Added changeset Signed-off-by: Gabriele Mambrini --- .changeset/nasty-impalas-travel.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nasty-impalas-travel.md diff --git a/.changeset/nasty-impalas-travel.md b/.changeset/nasty-impalas-travel.md new file mode 100644 index 0000000000..f6eb321628 --- /dev/null +++ b/.changeset/nasty-impalas-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Paths can be specified in backend.reading.allow to further restrict allowed targets From 0514f55ff1a12000c2f29014bd98f5ab8bcf1780 Mon Sep 17 00:00:00 2001 From: Gabriele Mambrini Date: Mon, 8 Nov 2021 17:56:07 +0100 Subject: [PATCH 4/5] Update config schema Signed-off-by: Gabriele Mambrini --- packages/backend-common/config.d.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/backend-common/config.d.ts b/packages/backend-common/config.d.ts index bc5e026375..dfc845f3b2 100644 --- a/packages/backend-common/config.d.ts +++ b/packages/backend-common/config.d.ts @@ -130,6 +130,14 @@ export interface Config { * The host may also contain a port, for example `example.com:8080`. */ host: string; + + /** + * An optional list of paths. In case they are present only targets matching + * any of them will are allowed. You can use trailing slashes to make sure only + * subdirectories are allowed, for example `/mydir/` will allow targets with + * paths like `/mydir/a` but will block paths like `/mydir2`. + */ + paths?: string[]; }>; }; From f14ac64f2e8446844a99f639727c3dd3feae125c Mon Sep 17 00:00:00 2001 From: Gabriele Mambrini Date: Mon, 8 Nov 2021 18:06:53 +0100 Subject: [PATCH 5/5] Use posix normaliser for URL paths Signed-off-by: Gabriele Mambrini --- packages/backend-common/src/reading/FetchUrlReader.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/backend-common/src/reading/FetchUrlReader.ts b/packages/backend-common/src/reading/FetchUrlReader.ts index 1ae9677a85..19bf5fb140 100644 --- a/packages/backend-common/src/reading/FetchUrlReader.ts +++ b/packages/backend-common/src/reading/FetchUrlReader.ts @@ -24,7 +24,7 @@ import { SearchResponse, UrlReader, } from './types'; -import { normalize as normalizePath } from 'path'; +import path from 'path'; /** * A UrlReader that does a plain fetch of the URL. @@ -52,8 +52,10 @@ export class FetchUrlReader implements UrlReader { const paths = allowConfig.getOptionalStringArray('paths'); const checkPath = paths ? (url: URL) => { - const targetPath = normalizePath(url.pathname); - return paths.some(path => targetPath.startsWith(path)); + const targetPath = path.posix.normalize(url.pathname); + return paths.some(allowedPath => + targetPath.startsWith(allowedPath), + ); } : (_url: URL) => true; const host = allowConfig.getString('host');