Skip to content

Commit 33d68ff

Browse files
authored
feat: split up team policies to single file (#2057)
1 parent d358c38 commit 33d68ff

File tree

87 files changed

+806
-344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+806
-344
lines changed

src/cmd/commit.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ const commitAndPush = async (values: Record<string, any>, branch: string): Promi
7070
}
7171
await $`git push -u origin ${branch}`
7272
} catch (e) {
73-
d.warn(`The values repository is not yet reachable.`)
74-
throw new Error('Could not commit and push. Retrying...')
73+
const errorMsg = 'Could not pull and push. Retrying...'
74+
d.error(errorMsg)
75+
throw new Error(errorMsg)
7576
}
7677
},
7778
{

src/cmd/migrate.test.ts

+58-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import { applyChanges, Changes, filterChanges, getBuildName } from 'src/cmd/migrate'
1+
import { applyChanges, Changes, filterChanges, getBuildName, policiesMigration } from 'src/cmd/migrate'
22
import stubs from 'src/test-stubs'
3+
import { globSync } from 'glob'
4+
import { getFileMap } from '../common/repo'
5+
import { env } from '../common/envalid'
36

47
jest.mock('uuid', () => ({
58
v4: jest.fn(() => 'my-fixed-uuid'),
@@ -567,3 +570,57 @@ describe('Build image name migration', () => {
567570
expect(deps.writeValues).toBeCalledWith(expectedValues, true)
568571
}, 20000)
569572
})
573+
574+
jest.mock('glob')
575+
describe('Policies migration', () => {
576+
const mockFilePaths = ['/path/to/env/teams/admin/policies.yaml', '/path/to/env/teams/alpha/policies.yaml']
577+
578+
const policiesFileMap = getFileMap('AplTeamPolicy', env.ENV_DIR)
579+
const mockYamlContent = {
580+
'/path/to/env/teams/admin/policies.yaml': {
581+
metadata: { name: 'admin' },
582+
spec: { ruleA: { action: 'Audit' } },
583+
},
584+
'/path/to/env/teams/alpha/policies.yaml': {
585+
metadata: { name: 'alpha' },
586+
spec: { ruleB: { action: 'Enforce' } },
587+
},
588+
}
589+
590+
const loadYaml = jest.fn((filePath: string) => mockYamlContent[filePath])
591+
const saveResourceGroupToFiles = jest.fn()
592+
593+
beforeEach(() => {
594+
jest.clearAllMocks()
595+
})
596+
597+
it('should load and convert policies.yaml files into teamConfig and save them', async () => {
598+
;(globSync as jest.Mock).mockReturnValue(mockFilePaths)
599+
600+
await policiesMigration({ loadYaml, saveResourceGroupToFiles })
601+
602+
expect(loadYaml).toHaveBeenCalledTimes(2)
603+
expect(loadYaml).toHaveBeenCalledWith('/path/to/env/teams/admin/policies.yaml')
604+
expect(loadYaml).toHaveBeenCalledWith('/path/to/env/teams/alpha/policies.yaml')
605+
606+
expect(saveResourceGroupToFiles).toHaveBeenCalledWith(
607+
policiesFileMap,
608+
{
609+
teamConfig: {
610+
admin: { policies: { ruleA: { action: 'Audit' } } },
611+
alpha: { policies: { ruleB: { action: 'Enforce' } } },
612+
},
613+
},
614+
{},
615+
)
616+
})
617+
618+
it('should not migrate if filepaths are empty', async () => {
619+
;(globSync as jest.Mock).mockReturnValue([])
620+
621+
await policiesMigration({ loadYaml, saveResourceGroupToFiles })
622+
623+
expect(loadYaml).toHaveBeenCalledTimes(0)
624+
expect(saveResourceGroupToFiles).toHaveBeenCalledTimes(0)
625+
})
626+
})

src/cmd/migrate.ts

+30-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import { randomUUID } from 'crypto'
55
import { diff } from 'deep-diff'
66
import { copy, createFileSync, move, pathExists, renameSync, rm } from 'fs-extra'
77
import { mkdir, readFile, writeFile } from 'fs/promises'
8-
import { glob } from 'glob'
8+
import { glob, globSync } from 'glob'
99
import { cloneDeep, each, get, isObject, isUndefined, mapKeys, mapValues, omit, pick, pull, set, unset } from 'lodash'
1010
import { basename, dirname, join } from 'path'
1111
import { prepareEnvironment } from 'src/common/cli'
1212
import { decrypt, encrypt } from 'src/common/crypt'
1313
import { terminal } from 'src/common/debug'
1414
import { env } from 'src/common/envalid'
1515
import { hf, hfValues } from 'src/common/hf'
16-
import { getFileMap, getTeamNames, saveValues } from 'src/common/repo'
16+
import { getFileMap, getTeamNames, saveResourceGroupToFiles, saveValues } from 'src/common/repo'
1717
import { getFilename, getSchemaSecretsPaths, gucci, loadYaml, rootDir } from 'src/common/utils'
1818
import { writeValues, writeValuesToFile } from 'src/common/values'
1919
import { BasicArguments, getParsedArgs, setParsedArgs } from 'src/common/yargs'
@@ -53,6 +53,7 @@ interface Change {
5353
networkPoliciesMigration?: boolean
5454
teamResourceQuotaMigration?: boolean
5555
buildImageNameMigration?: boolean
56+
policiesMigration?: boolean
5657
}
5758

5859
export type Changes = Array<Change>
@@ -310,6 +311,32 @@ export const getBuildName = (name: string, tag: string): string => {
310311
.replace(/^-|-$/g, '') // Remove leading or trailing hyphens
311312
}
312313

314+
export async function policiesMigration(deps = { loadYaml, saveResourceGroupToFiles }) {
315+
const filePaths = globSync(`${env.ENV_DIR}/env/teams/*/policies.yaml`, {
316+
nodir: true, // Exclude directories
317+
dot: false,
318+
}).sort()
319+
if (filePaths.length === 0) {
320+
console.info('No policies.yaml files found in env/teams/*/policies.yaml. Skipping migration')
321+
return
322+
}
323+
const inValues = filePaths.map(async (filePath) => {
324+
const yaml = await deps.loadYaml(filePath)
325+
return {
326+
[yaml!.metadata.name]: {
327+
policies: yaml!.spec,
328+
},
329+
}
330+
})
331+
const teamArray = await Promise.all(inValues)
332+
const teamConfig = teamArray.reduce((acc, team) => {
333+
return { ...acc, ...team }
334+
}, {})
335+
336+
const policiesFileMap = getFileMap('AplTeamPolicy', env.ENV_DIR)
337+
await deps.saveResourceGroupToFiles(policiesFileMap, { teamConfig }, {})
338+
}
339+
313340
const buildImageNameMigration = async (values: Record<string, any>): Promise<void> => {
314341
const teams: Array<string> = Object.keys(values?.teamConfig as Record<string, any>)
315342
type Build = {
@@ -412,6 +439,7 @@ export const applyChanges = async (
412439
if (c.networkPoliciesMigration) await networkPoliciesMigration(values)
413440
if (c.teamResourceQuotaMigration) teamResourceQuotaMigration(values)
414441
if (c.buildImageNameMigration) await buildImageNameMigration(values)
442+
if (c.policiesMigration) await policiesMigration()
415443

416444
Object.assign(values.versions, { specVersion: c.version })
417445
}

src/common/repo.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ describe('File map constraints', () => {
104104
const maps = getFileMaps('/tmp')
105105
maps.forEach((item) => {
106106
expect(item.jsonPathExpression.startsWith('$.')).toBe(true)
107-
if (item.processAs === 'arrayItem') {
107+
if (item.processAs === 'arrayItem' || item.kind === 'AplTeamPolicy') {
108108
expect(item.jsonPathExpression.endsWith('[*]')).toBe(true)
109109
}
110110
if (item.processAs === 'mapItem') {
111-
expect(item.jsonPathExpression.endsWith('[*]')).toBe(false)
111+
expect(item.jsonPathExpression.endsWith('[*]') && item.kind !== 'AplTeamPolicy').toBe(false)
112112
}
113113
if (item.resourceGroup === 'team') {
114114
expect(item.jsonPathExpression.startsWith('$.teamConfig.*.')).toBe(true)

src/common/repo.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ export function getResourceName(fileMap: FileMap, jsonPath: jsonpath.PathCompone
8181
return resourceName
8282
}
8383

84-
if (fileMap.resourceGroup === 'team') {
84+
// Custom workaround for teamPolicy because it is a mapItem
85+
if (fileMap.resourceGroup === 'team' && fileMap.kind !== 'AplTeamPolicy') {
8586
resourceName = getTeamNameFromJsonPath(jsonPath)
8687
return resourceName
8788
} else {
@@ -369,11 +370,11 @@ export function getFileMaps(envDir: string): Array<FileMap> {
369370
{
370371
kind: 'AplTeamPolicy',
371372
envDir,
372-
jsonPathExpression: '$.teamConfig.*.policies',
373-
pathGlob: `${envDir}/env/teams/*/policies.yaml`,
373+
jsonPathExpression: '$.teamConfig.*.policies[*]',
374+
pathGlob: `${envDir}/env/teams/*/policies/*.yaml`,
374375
processAs: 'mapItem',
375376
resourceGroup: 'team',
376-
resourceDir: '.',
377+
resourceDir: 'policies',
377378
loadToSpec: true,
378379
},
379380
]
@@ -595,6 +596,13 @@ export async function loadFileToSpec(
595596
if (fileMap.processAs === 'arrayItem') {
596597
const ref: Record<string, any>[] = get(spec, jsonPath)
597598
ref.push(data?.spec)
599+
} else if (fileMap.kind === 'AplTeamPolicy') {
600+
const ref: Record<string, any> = get(spec, jsonPath)
601+
const policy = {
602+
[data?.metadata?.name]: data?.spec,
603+
}
604+
const newRef = merge(cloneDeep(ref), policy)
605+
set(spec, jsonPath, newRef)
598606
} else {
599607
const ref: Record<string, any> = get(spec, jsonPath)
600608
// Decrypted secrets may need to be merged with plain text specs

tests/fixtures/env/teams/admin/policies.yaml

-111
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: allowed-image-repositories
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-capabilities-strict
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-capabilities
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
customValues:
9+
- AUDIT_WRITE
10+
- CHOWN
11+
- DAC_OVERRIDE
12+
- FOWNER
13+
- FSETID
14+
- KILL
15+
- MKNOD
16+
- NET_BIND_SERVICE
17+
- SETFCAP
18+
- SETGID
19+
- SETPCAP
20+
- SETUID
21+
- SYS_CHROOT
22+
- "''"
23+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-host-namespaces
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-host-path
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-host-ports
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-host-process
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
kind: AplTeamPolicy
2+
metadata:
3+
name: disallow-latest-tag
4+
labels:
5+
apl.io/teamId: admin
6+
spec:
7+
action: Audit
8+
severity: medium

0 commit comments

Comments
 (0)