Apply the rules enforcer, based on origin location
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -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,
|
||||
|
||||
+27
-2
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user