Apply the rules enforcer, based on origin location

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2021-09-21 16:49:54 +02:00
parent 29a89c1a9d
commit d6f90e934d
5 changed files with 85 additions and 3 deletions
+2
View File
@@ -751,6 +751,7 @@ export class DefaultCatalogProcessingOrchestrator
logger: Logger_2;
parser: CatalogProcessorParser;
policy: EntityPolicy;
rulesEnforcer: CatalogRulesEnforcer;
});
// (undocumented)
process(request: EntityProcessingRequest): Promise<EntityProcessingResult>;
@@ -1497,4 +1498,5 @@ export class UrlReaderProcessor implements CatalogProcessor {
// src/ingestion/processors/types.d.ts:58:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
// src/ingestion/types.d.ts:17:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
// src/ingestion/types.d.ts:41:8 - (tsdoc-param-tag-missing-hyphen) The @param block should be followed by a parameter name and then a hyphen
// src/next/processing/DefaultCatalogProcessingOrchestrator.d.ts:15:9 - (ae-forgotten-export) The symbol "CatalogRulesEnforcer" needs to be exported by the entry point index.d.ts
```
@@ -16,6 +16,7 @@
import { Config } from '@backstage/config';
import { LocationSpec, Entity } from '@backstage/catalog-model';
import path from 'path';
/**
* A structure for matching entities to a given rule.
@@ -104,7 +105,7 @@ export class CatalogRulesEnforcer {
return [];
}
const type = locConf.getString('type');
const target = locConf.getString('target');
const target = resolveTarget(type, locConf.getString('target'));
return locConf.getConfigArray('rules').map(ruleConf => ({
allow: ruleConf.getStringArray('allow').map(kind => ({ kind })),
@@ -175,3 +176,11 @@ export class CatalogRulesEnforcer {
return false;
}
}
function resolveTarget(type: string, target: string): string {
if (type !== 'file') {
return target;
}
return path.resolve(target);
}
@@ -78,6 +78,7 @@ import {
import { CatalogEnvironment } from '../service/CatalogBuilder';
import { createNextRouter } from './NextRouter';
import { DefaultRefreshService } from './DefaultRefreshService';
import { CatalogRulesEnforcer } from '../ingestion/CatalogRules';
/**
* A builder that helps wire up all of the component parts of the catalog.
@@ -304,9 +305,11 @@ export class NextCatalogBuilder {
refreshInterval: this.refreshInterval,
});
const integrations = ScmIntegrations.fromConfig(config);
const rulesEnforcer = CatalogRulesEnforcer.fromConfig(config);
const orchestrator = new DefaultCatalogProcessingOrchestrator({
processors,
integrations,
rulesEnforcer,
logger,
parser,
policy,
@@ -21,8 +21,9 @@ import {
LocationSpec,
parseLocationReference,
stringifyEntityRef,
stringifyLocationReference,
} from '@backstage/catalog-model';
import { ConflictError, InputError } from '@backstage/errors';
import { ConflictError, InputError, NotAllowedError } from '@backstage/errors';
import { ScmIntegrationRegistry } from '@backstage/integration';
import path from 'path';
import { Logger } from 'winston';
@@ -45,6 +46,7 @@ import {
validateEntity,
validateEntityEnvelope,
} from './util';
import { CatalogRulesEnforcer } from '../../ingestion/CatalogRules';
type Context = {
entityRef: string;
@@ -63,6 +65,7 @@ export class DefaultCatalogProcessingOrchestrator
logger: Logger;
parser: CatalogProcessorParser;
policy: EntityPolicy;
rulesEnforcer: CatalogRulesEnforcer;
},
) {}
@@ -117,8 +120,30 @@ export class DefaultCatalogProcessingOrchestrator
}
entity = await this.runPostProcessStep(entity, context);
// Check that any emitted entities are permitted to originate from that
// particular location according to the catalog rules
const collectorResults = context.collector.results();
for (const deferredEntity of collectorResults.deferredEntities) {
if (
!this.options.rulesEnforcer.isAllowed(
deferredEntity.entity,
context.originLocation,
)
) {
throw new NotAllowedError(
`Entity ${stringifyEntityRef(
deferredEntity.entity,
)} at ${stringifyLocationReference(
context.location,
)}, originated at ${stringifyLocationReference(
context.originLocation,
)}, is not of an allowed kind for that location`,
);
}
}
return {
...context.collector.results(),
...collectorResults,
completedEntity: entity,
state: new Map(),
ok: true,