Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/sample-settings/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ rulesets:
# - pull_request
bypass_mode: pull_request

- actor_id: 1
# actor_id must be null for OrganizationAdmin: GitHub ignores the id for
# this actor type and returns null, so any other value never converges
- actor_id: null
actor_type: OrganizationAdmin
bypass_mode: always

Expand Down
7 changes: 4 additions & 3 deletions lib/mergeDeep.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const mergeBy = require('./mergeArrayBy')
const DeploymentConfig = require('./deploymentConfig')

const NAME_FIELDS = ['name', 'username', 'actor_id', 'login', 'type', 'key_prefix', 'context']
const NAME_USERNAME_PROPERTY = item => NAME_FIELDS.find(prop => Object.prototype.hasOwnProperty.call(item, prop))
const IDENTITY_FIELDS = ['name', 'username', 'actor_id', 'actor_type', 'login', 'type', 'key_prefix', 'context']
const NAME_USERNAME_PROPERTY = item => IDENTITY_FIELDS.find(prop => Object.prototype.hasOwnProperty.call(item, prop) && item[prop] != null)
const GET_NAME_USERNAME_PROPERTY = item => { if (NAME_USERNAME_PROPERTY(item)) return item[NAME_USERNAME_PROPERTY(item)] }
Comment thread
tdabasinskas marked this conversation as resolved.

class MergeDeep {
Expand Down Expand Up @@ -92,8 +93,8 @@ class MergeDeep {
// So any property in the target that is not in the source is not treated as a deletion
for (const key in source) {
// Skip prototype pollution vectors
if (key === "__proto__" || key === "constructor") {
continue;
if (key === '__proto__' || key === 'constructor') {
continue
}
// Logic specific for Github
// API response includes urls for resources, or other ignorable fields; we can ignore them
Expand Down
30 changes: 30 additions & 0 deletions test/unit/lib/mergeDeep.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1882,4 +1882,34 @@ branches:
expect(same.additions).toEqual({})
expect(same.modifications).toEqual({})
})

describe('CompareDeep bypass actors with a null actor_id (OrganizationAdmin, DeployKey)', () => {
// GitHub ignores actor_id for these actor types and always returns
// actor_id: null, so the config should carry null and still diff correctly.
const mergeDeep = new MergeDeep(log, jest.fn(), [])
const orgAdmin = { actor_id: null, actor_type: 'OrganizationAdmin', bypass_mode: 'pull_request' }
const app = { actor_id: 210920, actor_type: 'Integration', bypass_mode: 'always' }

it('deploys a config-only actor from an empty ruleset', () => {
const result = mergeDeep.compareDeep({ bypass_actors: [] }, { bypass_actors: [orgAdmin] })
expect(result.hasChanges).toEqual(true)
expect(result.additions.bypass_actors).toEqual([orgAdmin])
})

it('deploys a config-only actor alongside an existing app actor', () => {
const result = mergeDeep.compareDeep({ bypass_actors: [app] }, { bypass_actors: [app, orgAdmin] })
expect(result.hasChanges).toEqual(true)
expect(result.additions.bypass_actors).toEqual([orgAdmin])
})

it('converges once the actor is live', () => {
const result = mergeDeep.compareDeep({ bypass_actors: [orgAdmin] }, { bypass_actors: [orgAdmin] })
expect(result.hasChanges).toEqual(false)
})

it('converges with mixed actors and still identifies real ids by actor_id', () => {
const result = mergeDeep.compareDeep({ bypass_actors: [app, orgAdmin] }, { bypass_actors: [app, orgAdmin] })
expect(result.hasChanges).toEqual(false)
})
Comment thread
tdabasinskas marked this conversation as resolved.
})
})