Merge pull request #7892 from gmambro/allow-prefix
Optional paths in backend.reading.allow to restrict allowed targets
This commit is contained in:
@@ -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
|
||||
|
||||
Vendored
+8
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user