@ossy/deployment-tools 3.7.0 → 3.13.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,24 @@
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.13.0](https://github.com/ossy-se/ossy/compare/v3.12.0...v3.13.0) (2026-09-06)
7
+
8
+ ### Features
9
+
10
+ * **platform:** download GeoLite2-Country at startServer boot ([#804](https://github.com/ossy-se/ossy/issues/804)) ([#818](https://github.com/ossy-se/ossy/issues/818)) ([6629ad0](https://github.com/ossy-se/ossy/commit/6629ad07277cfa8350759f2a775110a00743c393))
11
+
12
+
13
+ # [3.12.0](https://github.com/ossy-se/ossy/compare/v3.11.1...v3.12.0) (2026-09-06)
14
+
15
+ ### Bug Fixes
16
+
17
+ * default the API to same-origin and drop api.ossy.se ([#794](https://github.com/ossy-se/ossy/issues/794)) ([397a06f](https://github.com/ossy-se/ossy/commit/397a06f88b01e297fb76f35c429f3e687bdd6af9))
18
+
19
+ ### Features
20
+
21
+ * **analytics:** Host visitor locations from connection geo ([#772](https://github.com/ossy-se/ossy/issues/772)) ([a565c1b](https://github.com/ossy-se/ossy/commit/a565c1b5078219ef412148d77dc33697f2079612)), closes [#769](https://github.com/ossy-se/ossy/issues/769) [#797](https://github.com/ossy-se/ossy/issues/797) [#797](https://github.com/ossy-se/ossy/issues/797) [#797](https://github.com/ossy-se/ossy/issues/797) [#797](https://github.com/ossy-se/ossy/issues/797) [#769](https://github.com/ossy-se/ossy/issues/769) [#797](https://github.com/ossy-se/ossy/issues/797) [#769](https://github.com/ossy-se/ossy/issues/769)
22
+
23
+
6
24
  # [3.7.0](https://github.com/ossy-se/ossy/compare/v3.6.2...v3.7.0) (2026-08-22)
7
25
 
8
26
  ### Features
package/README.md CHANGED
@@ -9,7 +9,7 @@ Infrastructure and CDK tooling for the Ossy platform.
9
9
  ```
10
10
  Internet → CloudFront (ACM TLS, us-east-1) → WAF → ALB (:80)
11
11
  ├── host rules from platforms.json `services[].hosts|domain`
12
- │ e.g. ossy.se, api.ossy.se → website-ossy Fargate service
12
+ │ e.g. ossy.se → website-ossy Fargate service
13
13
  ├── other known hosts / *.ossy.se → platform-runtime Fargate service
14
14
  └── default action → platform-runtime
15
15
  ```
@@ -35,7 +35,7 @@ Every deployable Ossy HTTP image exposes an unauthenticated liveness probe at **
35
35
 
36
36
  **ALB target groups** probe `GET /health`. **ECS container health checks** run an exec-form Node one-liner (`ecsContainerHealthCheckCommand`) that `fetch`es the same path on `PORT` and aborts after `HEALTHCHECK_FETCH_TIMEOUT_MS` (4s). Do not point probes at `/`, `/status`, or authenticated routes.
37
37
 
38
- Task definitions also set plain env `PORT`, `OSSY_SERVICE_NAME`, `NODE_ENV`, and media bucket vars via `containerEnvironment`. Those keys are **filtered out** of Secrets Manager injection (`secretEnvKeysForEcsContainer`) so ECS cannot reject duplicate environment/secret keys.
38
+ Task definitions also set plain env `PORT`, `OSSY_SERVICE_NAME`, `NODE_ENV`, media bucket vars, and `GEOLITE2_COUNTRY_MMDB` (`/tmp/GeoLite2-Country.mmdb`, #804) via `containerEnvironment`. Those keys are **filtered out** of Secrets Manager injection (`secretEnvKeysForEcsContainer`) so ECS cannot reject duplicate environment/secret keys.
39
39
 
40
40
  ## Configuration — `platforms.json`
41
41
 
@@ -64,7 +64,7 @@ HTTP services (default) become Fargate services with ALB host rules. The contain
64
64
  "name": "ossy-website-ossy",
65
65
  "domain": "ossy.se",
66
66
  "image": "ghcr.io/ossy-se/website-ossy:latest",
67
- "hosts": ["ossy.se", "api.ossy.se"]
67
+ "hosts": ["ossy.se"]
68
68
  }
69
69
  ]
70
70
  ```
@@ -73,7 +73,7 @@ HTTP services (default) become Fargate services with ALB host rules. The contain
73
73
  |---|---|
74
74
  | `name` | Unique service name — Secrets Manager / ECS key strips a leading `ossy-` (`website-ossy`). |
75
75
  | `domain` | Primary hostname (default ALB host when `hosts` is omitted). |
76
- | `hosts` | Optional ALB host-header list. Example: `["ossy.se","api.ossy.se"]` so the website image serves apex and API host. Defaults to `[domain]`. |
76
+ | `hosts` | Optional ALB host-header list. Example: `["ossy.se"]` so the website image serves the apex. Defaults to `[domain]`. |
77
77
  | `image` | Docker image to pull and run (GHCR). |
78
78
 
79
79
  **Built-in (always present):**
@@ -264,6 +264,10 @@ Other common env vars:
264
264
  | `AWS_SECRET_ACCESS_KEY` | API | AWS credentials for S3 |
265
265
  | `OSSY_API_KEY` | Platform, websites | API JWT for CMS reads |
266
266
  | `OSSY_COOKIE_SECRET` | Websites | Cookie signing secret |
267
+ | `GEOLITE2_COUNTRY_MMDB` | App (`@ossy/analytics` location projection) | Absolute path to MaxMind GeoLite2-Country `.mmdb` (#769 / #804). Set on every ECS task as `/tmp/GeoLite2-Country.mmdb`. `startServer` downloads the file there when `MAXMIND_LICENSE_KEY` is set. Optional; without the file `countryCode` is omitted (IP still stored on the event). |
268
+ | `MAXMIND_LICENSE_KEY` | App (`startServer` GeoLite2 download) | MaxMind license key. Add to `platforms.json` `env` and `npm run sync-secrets` so **every** website image (ossy.se, plexus-sanitas, …) can download GeoLite2-Country at boot (#804). Free signup: https://www.maxmind.com/en/geolite2/signup |
269
+ | `MAXMIND_ACCOUNT_ID` | App (`startServer` GeoLite2 download) | Optional MaxMind account id. When set with the license key, download uses the permalink + HTTP Basic auth API. |
270
+ | `OSSY_TRUST_PROXY_HOPS` | Platform / websites | Express `trust proxy` hop count behind CloudFront→ALB (default: `2`). |
267
271
  | `OPENAI_API_KEY` | Worker | OpenAI API key |
268
272
  | `OPENAI_ORGANIZATION` | Worker | OpenAI organisation ID |
269
273
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/deployment-tools",
3
- "version": "3.7.0",
3
+ "version": "3.13.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": "622d97535abad08415963405ace2f5aaaecd7ca4"
27
+ "gitHead": "7a02d1e056b731aa36f72e3f8d6df941101dbd50"
28
28
  }
@@ -31,8 +31,12 @@ const CONTAINER_ENVIRONMENT_KEYS = Object.freeze([
31
31
  'OSSY_SERVICE_NAME',
32
32
  'MEDIA_REPOSITORY',
33
33
  'MEDIA_CDN_DOMAIN_NAME',
34
+ 'GEOLITE2_COUNTRY_MMDB',
34
35
  ])
35
36
 
37
+ /** Keep in sync with `@ossy/platform` `GEOLITE2_COUNTRY_MMDB_PATH` (#804). */
38
+ const GEOLITE2_COUNTRY_MMDB_PATH = '/tmp/GeoLite2-Country.mmdb'
39
+
36
40
  /**
37
41
  * @typedef {Object} PlatformEcsService
38
42
  * @property {string} key - short key (`runtime`, `website-ossy`, …) — matches Secrets Manager
@@ -96,6 +100,7 @@ function containerEnvironment({
96
100
  OSSY_SERVICE_NAME: serviceKey,
97
101
  MEDIA_REPOSITORY: mediaRepository,
98
102
  MEDIA_CDN_DOMAIN_NAME: mediaCdnDomainName,
103
+ GEOLITE2_COUNTRY_MMDB: GEOLITE2_COUNTRY_MMDB_PATH,
99
104
  ...(nodeOptions ? { NODE_OPTIONS: nodeOptions } : {}),
100
105
  }
101
106
  }
@@ -212,6 +217,7 @@ module.exports = {
212
217
  CONTAINER_PORT,
213
218
  HEALTH_PATH,
214
219
  HEALTHCHECK_FETCH_TIMEOUT_MS,
220
+ GEOLITE2_COUNTRY_MMDB_PATH,
215
221
  CONTAINER_ENVIRONMENT_KEYS,
216
222
  secretEnvKeysForEcsContainer,
217
223
  containerEnvironment,
@@ -6,6 +6,7 @@ const {
6
6
  CONTAINER_PORT,
7
7
  HEALTH_PATH,
8
8
  HEALTHCHECK_FETCH_TIMEOUT_MS,
9
+ GEOLITE2_COUNTRY_MMDB_PATH,
9
10
  RUNTIME_IMAGE,
10
11
  containerEnvironment,
11
12
  ecsContainerHealthCheckCommand,
@@ -27,6 +28,17 @@ describe('shared health constants', () => {
27
28
  })
28
29
  })
29
30
 
31
+ describe('GeoLite2-Country path (#804)', () => {
32
+ it('stays aligned with @ossy/platform geolite2-country-path.js', () => {
33
+ const src = fs.readFileSync(
34
+ path.join(__dirname, '../../../platform/src/geoip/geolite2-country-path.js'),
35
+ 'utf8'
36
+ )
37
+ expect(src).toContain(`export const GEOLITE2_COUNTRY_MMDB_PATH = '${GEOLITE2_COUNTRY_MMDB_PATH}'`)
38
+ expect(GEOLITE2_COUNTRY_MMDB_PATH).toBe('/tmp/GeoLite2-Country.mmdb')
39
+ })
40
+ })
41
+
30
42
  describe('ecsContainerHealthCheckCommand', () => {
31
43
  it('probes HEALTH_PATH with Node fetch and abort timeout', () => {
32
44
  const command = ecsContainerHealthCheckCommand()
@@ -60,6 +72,7 @@ describe('containerEnvironment', () => {
60
72
  OSSY_SERVICE_NAME: 'website-ossy',
61
73
  MEDIA_REPOSITORY: 'media-bucket',
62
74
  MEDIA_CDN_DOMAIN_NAME: 'https://cdn.example',
75
+ GEOLITE2_COUNTRY_MMDB: '/tmp/GeoLite2-Country.mmdb',
63
76
  })
64
77
  })
65
78
 
@@ -92,6 +105,7 @@ describe('secretEnvKeysForEcsContainer', () => {
92
105
  'TOKEN_SECRET',
93
106
  'NODE_ENV',
94
107
  'MEDIA_REPOSITORY',
108
+ 'GEOLITE2_COUNTRY_MMDB',
95
109
  'NODE_OPTIONS',
96
110
  'DB_URL',
97
111
  ])).toEqual(['TOKEN_SECRET', 'DB_URL'])
@@ -106,8 +120,8 @@ describe('hostsFromServiceEntry', () => {
106
120
  it('uses hosts when provided', () => {
107
121
  expect(hostsFromServiceEntry({
108
122
  domain: 'ossy.se',
109
- hosts: ['ossy.se', 'api.ossy.se'],
110
- })).toEqual(['ossy.se', 'api.ossy.se'])
123
+ hosts: ['ossy.se', 'www.ossy.se'],
124
+ })).toEqual(['ossy.se', 'www.ossy.se'])
111
125
  })
112
126
 
113
127
  it('falls back to domain', () => {
@@ -120,7 +134,6 @@ describe('listPlatformEcsServices', () => {
120
134
  const services = listPlatformEcsServices({
121
135
  platformName: 'ossybot',
122
136
  domains: [
123
- 'api.ossy.se',
124
137
  'ossy.se',
125
138
  '*.ossy.se',
126
139
  'www.plexus-sanitas.com',
@@ -130,7 +143,7 @@ describe('listPlatformEcsServices', () => {
130
143
  {
131
144
  name: 'ossy-website-ossy',
132
145
  domain: 'ossy.se',
133
- hosts: ['ossy.se', 'api.ossy.se'],
146
+ hosts: ['ossy.se'],
134
147
  image: 'ghcr.io/ossy-se/website-ossy:latest',
135
148
  cpu: 1024,
136
149
  memoryLimitMiB: 4096,
@@ -165,7 +178,7 @@ describe('listPlatformEcsServices', () => {
165
178
 
166
179
  const website = services.find(s => s.key === 'website-ossy')
167
180
  expect(website.isDefault).toBe(false)
168
- expect(website.hosts).toEqual(['ossy.se', 'api.ossy.se'])
181
+ expect(website.hosts).toEqual(['ossy.se'])
169
182
  expect(website.image).toBe('ghcr.io/ossy-se/website-ossy:latest')
170
183
  expect(website.secretName).toBe('ossybot/website-ossy')
171
184
  expect(website.cpu).toBe(1024)
@@ -193,7 +193,7 @@ class PlatformEcsStack extends Stack {
193
193
  streamPrefix: service.key,
194
194
  logGroup,
195
195
  }),
196
- // Labels `/health` via OSSY_SERVICE_NAME; keys stay in CONTAINER_ENVIRONMENT_KEYS.
196
+ // Labels `/health` via OSSY_SERVICE_NAME; GeoLite2 path (#804). Keys stay in CONTAINER_ENVIRONMENT_KEYS.
197
197
  environment: containerEnvironment({
198
198
  serviceKey: service.key,
199
199
  containerPort: service.containerPort,
@@ -281,7 +281,7 @@ class PlatformEcsStack extends Stack {
281
281
  })
282
282
 
283
283
  // Lower priority number = evaluated first. Specific hosts before wildcards
284
- // so `api.ossy.se` is not swallowed by `*.ossy.se`.
284
+ // so `ossy.se` is not swallowed by `*.ossy.se`.
285
285
  // Priorities are hash-stable per host — sequential 10,11,12… renumbers
286
286
  // every insert and CloudFormation cannot swap ALB priorities in one update.
287
287
  const usedPriorities = new Set()