Merge pull request #7892 from gmambro/allow-prefix

Optional paths in backend.reading.allow to restrict allowed targets
This commit is contained in:
Fredrik Adelöw
2021-11-16 16:29:33 +01:00
committed by GitHub
5 changed files with 39 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-common': patch
---
Paths can be specified in backend.reading.allow to further restrict allowed targets
@@ -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
+8
View File
@@ -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[];
}>;
};
@@ -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', () => {
@@ -24,6 +24,7 @@ import {
SearchResponse,
UrlReader,
} from './types';
import path from 'path';
/**
* A UrlReader that does a plain fetch of the URL.
@@ -39,18 +40,30 @@ 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 = path.posix.normalize(url.pathname);
return paths.some(allowedPath =>
targetPath.startsWith(allowedPath),
);
}
: (_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();