@ossy/deployment-tools 3.4.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [3.6.0](https://github.com/ossy-se/ossy/compare/v3.5.1...v3.6.0) (2026-08-16)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **deployment-tools:** stabilize ECS cutover edge, OIDC, and ALB rules ([#657](https://github.com/ossy-se/ossy/issues/657)) ([257bd79](https://github.com/ossy-se/ossy/commit/257bd7965d86a09aae2b8f285c5e22e2d29160bb))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# [3.4.0](https://github.com/ossy-se/ossy/compare/v3.3.0...v3.4.0) (2026-08-14)
|
|
7
14
|
|
|
8
15
|
### Features
|
package/cdk.context.json
CHANGED
|
@@ -84,5 +84,18 @@
|
|
|
84
84
|
"hosted-zone:account=858451553223:domainName=tepit.se:region=eu-north-1": {
|
|
85
85
|
"Id": "/hostedzone/Z07859112SU1GH5SKMUXD",
|
|
86
86
|
"Name": "tepit.se."
|
|
87
|
+
},
|
|
88
|
+
"availability-zones:account=858451553223:region=eu-north-1": [
|
|
89
|
+
"eu-north-1a",
|
|
90
|
+
"eu-north-1b",
|
|
91
|
+
"eu-north-1c"
|
|
92
|
+
],
|
|
93
|
+
"hosted-zone:account=858451553223:domainName=ossy.se:region=us-east-1": {
|
|
94
|
+
"Id": "/hostedzone/Z09424571CVOTIJV8Z50C",
|
|
95
|
+
"Name": "ossy.se."
|
|
96
|
+
},
|
|
97
|
+
"hosted-zone:account=858451553223:domainName=plexus-sanitas.com:region=us-east-1": {
|
|
98
|
+
"Id": "/hostedzone/Z0222639MQIJ8EOL9VAG",
|
|
99
|
+
"Name": "plexus-sanitas.com."
|
|
87
100
|
}
|
|
88
101
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/deployment-tools",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.0",
|
|
4
4
|
"description": "Collection of scripts and tools to aid deployment of containers and static files to Amazon Web Services through GitHub Actions",
|
|
5
5
|
"source": "./src/index.js",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"jest": "^30.4.2"
|
|
26
26
|
},
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "d1fd144986b0e819d46926aeb11f7815ac52a784"
|
|
28
28
|
}
|
|
@@ -28,8 +28,29 @@ function rootDomainOf(domain) {
|
|
|
28
28
|
return parts.slice(-2).join('.')
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Whether `hostname` is already covered by a `*.root` wildcard in `aliases`.
|
|
33
|
+
* CloudFront rejects overlapping CNAMEs (e.g. both `*.ossy.se` and `api.ossy.se`).
|
|
34
|
+
*
|
|
35
|
+
* @param {string} hostname
|
|
36
|
+
* @param {string[]} aliases
|
|
37
|
+
* @returns {boolean}
|
|
38
|
+
*/
|
|
39
|
+
function coveredByWildcardAlias(hostname, aliases) {
|
|
40
|
+
if (!hostname || hostname.includes('*')) return false
|
|
41
|
+
return aliases.some(alias => {
|
|
42
|
+
if (!alias.startsWith('*.')) return false
|
|
43
|
+
const suffix = alias.slice(1) // e.g. ".ossy.se"
|
|
44
|
+
if (!hostname.endsWith(suffix)) return false
|
|
45
|
+
const prefix = hostname.slice(0, -suffix.length)
|
|
46
|
+
// single-label subdomain only (*.ossy.se covers api.ossy.se, not a.b.ossy.se)
|
|
47
|
+
return prefix.length > 0 && !prefix.includes('.')
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
31
51
|
/**
|
|
32
52
|
* Unique, stable sorted list of CloudFront aliases from `domains` + HTTP service hosts.
|
|
53
|
+
* Drops hostnames covered by a sibling wildcard so ACM/CloudFront accept the set.
|
|
33
54
|
*
|
|
34
55
|
* @param {{
|
|
35
56
|
* domains?: string[],
|
|
@@ -46,9 +67,10 @@ function listEdgeAliases(config) {
|
|
|
46
67
|
return entry.domain ? [entry.domain] : []
|
|
47
68
|
})
|
|
48
69
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
70
|
+
const all = [...new Set([...fromDomains, ...fromServices])]
|
|
71
|
+
return all
|
|
72
|
+
.filter(alias => !coveredByWildcardAlias(alias, all))
|
|
73
|
+
.sort((a, b) => a.localeCompare(b))
|
|
52
74
|
}
|
|
53
75
|
|
|
54
76
|
/**
|
|
@@ -14,7 +14,7 @@ describe('rootDomainOf', () => {
|
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
describe('listEdgeAliases', () => {
|
|
17
|
-
it('unions domains and HTTP service hosts; skips tcp', () => {
|
|
17
|
+
it('unions domains and HTTP service hosts; skips tcp; drops names under wildcards', () => {
|
|
18
18
|
expect(listEdgeAliases({
|
|
19
19
|
domains: ['ossy.se', '*.ossy.se', 'worker.ossy.se'],
|
|
20
20
|
services: [
|
|
@@ -30,7 +30,7 @@ describe('listEdgeAliases', () => {
|
|
|
30
30
|
ports: [25565],
|
|
31
31
|
},
|
|
32
32
|
],
|
|
33
|
-
})).toEqual(['*.ossy.se', '
|
|
33
|
+
})).toEqual(['*.ossy.se', 'ossy.se'])
|
|
34
34
|
})
|
|
35
35
|
})
|
|
36
36
|
|
|
@@ -59,17 +59,14 @@ describe('planEdgeDomains', () => {
|
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
expect(plan.primaryDomain).toBe('ossy.se')
|
|
62
|
+
// api/worker covered by *.ossy.se — CloudFront forbids overlapping CNAMEs
|
|
62
63
|
expect(plan.aliases).toEqual([
|
|
63
64
|
'*.ossy.se',
|
|
64
|
-
'api.ossy.se',
|
|
65
65
|
'ossy.se',
|
|
66
|
-
'worker.ossy.se',
|
|
67
66
|
'www.plexus-sanitas.com',
|
|
68
67
|
])
|
|
69
68
|
expect(plan.subjectAlternativeNames).toEqual([
|
|
70
69
|
'*.ossy.se',
|
|
71
|
-
'api.ossy.se',
|
|
72
|
-
'worker.ossy.se',
|
|
73
70
|
'www.plexus-sanitas.com',
|
|
74
71
|
])
|
|
75
72
|
expect(plan.validationDomainToRoot.get('*.ossy.se')).toBe('ossy.se')
|
|
@@ -23,8 +23,9 @@ const {
|
|
|
23
23
|
* Trust is limited to `ref:refs/heads/main` for `config.githubDeployRepos`
|
|
24
24
|
* (set in platforms.json — add a repo there to allow it to assume this role).
|
|
25
25
|
*
|
|
26
|
-
* Note: AWS allows only one OIDC provider per URL per account. This stack
|
|
27
|
-
*
|
|
26
|
+
* Note: AWS allows only one OIDC provider per URL per account. This stack
|
|
27
|
+
* references the account provider (often created earlier by `trust-ci`) instead
|
|
28
|
+
* of creating a second one.
|
|
28
29
|
*/
|
|
29
30
|
class PlatformCiStack extends Stack {
|
|
30
31
|
/**
|
|
@@ -61,10 +62,12 @@ class PlatformCiStack extends Stack {
|
|
|
61
62
|
return `repo:${repo}:ref:refs/heads/main`
|
|
62
63
|
})
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
// One provider per issuer URL per account — reuse the existing GitHub OIDC IdP.
|
|
66
|
+
const provider = OpenIdConnectProvider.fromOpenIdConnectProviderArn(
|
|
67
|
+
this,
|
|
68
|
+
'GithubOidcProvider',
|
|
69
|
+
`arn:aws:iam::${account}:oidc-provider/token.actions.githubusercontent.com`
|
|
70
|
+
)
|
|
68
71
|
|
|
69
72
|
const deployRole = new Role(this, 'GithubDeployRole', {
|
|
70
73
|
roleName,
|
|
@@ -281,23 +281,18 @@ class PlatformEcsStack extends Stack {
|
|
|
281
281
|
|
|
282
282
|
// Lower priority number = evaluated first. Specific hosts before wildcards
|
|
283
283
|
// so `api.ossy.se` is not swallowed by `*.ossy.se`.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
let rulePriority = 10
|
|
291
|
-
for (const rule of orderedHostRules) {
|
|
284
|
+
// Priorities are hash-stable per host — sequential 10,11,12… renumbers
|
|
285
|
+
// every insert and CloudFormation cannot swap ALB priorities in one update.
|
|
286
|
+
const usedPriorities = new Set()
|
|
287
|
+
for (const rule of hostRules) {
|
|
292
288
|
listener.addTargetGroups(
|
|
293
289
|
`Rule${rule.idSuffix}${toConstructId(rule.host)}`,
|
|
294
290
|
{
|
|
295
|
-
priority:
|
|
291
|
+
priority: albHostRulePriority(rule.host, usedPriorities),
|
|
296
292
|
conditions: [ListenerCondition.hostHeaders([rule.host])],
|
|
297
293
|
targetGroups: [rule.targetGroup],
|
|
298
294
|
}
|
|
299
295
|
)
|
|
300
|
-
rulePriority += 1
|
|
301
296
|
}
|
|
302
297
|
|
|
303
298
|
this.vpc = vpc
|
|
@@ -325,6 +320,29 @@ class PlatformEcsStack extends Stack {
|
|
|
325
320
|
}
|
|
326
321
|
}
|
|
327
322
|
|
|
323
|
+
/**
|
|
324
|
+
* Stable ALB listener-rule priority for a host header (1–50000).
|
|
325
|
+
* Specific hosts: 10000–29999; wildcards: 40000–49999 (evaluated later).
|
|
326
|
+
* @param {string} host
|
|
327
|
+
* @param {Set<number>} used
|
|
328
|
+
* @returns {number}
|
|
329
|
+
*/
|
|
330
|
+
function albHostRulePriority(host, used) {
|
|
331
|
+
const band = host.includes('*') ? 40000 : 10000
|
|
332
|
+
let hash = 2166136261
|
|
333
|
+
for (let i = 0; i < host.length; i += 1) {
|
|
334
|
+
hash ^= host.charCodeAt(i)
|
|
335
|
+
hash = Math.imul(hash, 16777619) >>> 0
|
|
336
|
+
}
|
|
337
|
+
let priority = band + (hash % 20000)
|
|
338
|
+
while (used.has(priority)) {
|
|
339
|
+
priority += 1
|
|
340
|
+
if (priority >= band + 20000) priority = band
|
|
341
|
+
}
|
|
342
|
+
used.add(priority)
|
|
343
|
+
return priority
|
|
344
|
+
}
|
|
345
|
+
|
|
328
346
|
/**
|
|
329
347
|
* CloudFormation-safe construct id fragment.
|
|
330
348
|
* @param {string} key
|
|
@@ -346,4 +364,5 @@ function truncateAwsName(name, max) {
|
|
|
346
364
|
|
|
347
365
|
module.exports = {
|
|
348
366
|
PlatformEcsStack,
|
|
367
|
+
albHostRulePriority,
|
|
349
368
|
}
|