Skip to content

feat: warm pool — stop/start idle runners for fast restart#5204

Draft
Brend-Smits wants to merge 19 commits into
mainfrom
feature/warm-pool-hibernation
Draft

feat: warm pool — stop/start idle runners for fast restart#5204
Brend-Smits wants to merge 19 commits into
mainfrom
feature/warm-pool-hibernation

Conversation

@Brend-Smits

Copy link
Copy Markdown
Contributor

Description

Adds a warm pool feature that reduces runner startup latency from 2–5 minutes to 10–30 seconds by stopping idle instances instead of terminating them.

Three-tier instance lifecycle:

  • Hot (running) — 0s startup, full compute cost
  • Warm (stopped) — 10–30s startup, EBS-only cost
  • Cold (terminated) — 2–5 min startup, zero cost

Key components:

  • DynamoDB state table for warm pool tracking
  • Scale-down: stops instances instead of terminating (with AMI staleness eviction)
  • Scale-up: queries DynamoDB and starts warm instances before cold-launching
  • Pool lambda: pool_strategy = "warm" for zero-idle-compute deployments
  • Full spot instance support via persistent spot requests
  • CloudWatch metrics: WarmPoolStartLatency, WarmPoolEvicted, etc.

See docs/warm-pool.md and ADR-001 for full design.

Test Plan

  • 540 unit tests passing (vitest)
  • 6 Terraform integration tests (warm-pool.tftest.hcl)
  • Manual validation of DynamoDB operations and EC2 stop/start in dev environment

Related Issues

N/A — new feature

Brend-Smits and others added 15 commits July 9, 2026 15:55
- ADR documenting the warm pool concept with three instance states (hot/warm/cold)
- Implementation plan with phased approach
- User-facing warm pool configuration guide

Signed-off-by: Brend Smits <brend.smits@philips.com>
…, IAM

- Add warm_pool_config and pool_strategy variables to root, runners, and multi-runner modules
- Create DynamoDB table with GSI by-owner and TTL for warm pool state
- Add IAM policies for scale-down, scale-up, and pool lambdas (DynamoDB + EC2 stop/start)
- Wire WARM_POOL_CONFIG, WARM_POOL_TABLE_NAME, POOL_STRATEGY env vars to all lambdas
- Add enable_warm_pool metric toggle
- Cross-variable validation: pool_strategy=warm requires warm_pool_config.enabled=true

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Add warm-pool.ts with DynamoDB operations (add, remove, get, list, count)
- Add stopRunner() and startRunner() to runners.ts
- Add emitWarmPoolMetric() for CloudWatch metric publishing
- Export getWarmPoolConfig() and getPoolStrategy() helpers

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Modify removeRunner() to stop instances into warm pool when enabled
- Add DynamoDB record on stop with ghr:warm-pool-member tag
- Respect maxWarmInstances cap (terminate if full)
- Add evictStaleWarmInstances() for periodic cleanup:
  - Evict instances exceeding maxWarmAgeHours
  - Evict instances exceeding maxWarmInstances count
  - Emit WarmPoolSize metric after eviction

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Add findAndStartWarmRunners() to query DynamoDB and start stopped instances
- Integrate warm pool lookup before cold-launching new runners
- Handle org-level fallback when repo-level owner has no warm instances
- Write runner registration config (SSM) for restarted warm instances
- Tag started instances with ghr:started-from-warm-pool, remove ghr:warm-pool-member
- Emit WarmPoolInstanceStarted/WarmPoolStartFailed metrics
- Self-heal stale DynamoDB records on start failure

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Pool counts warm (stopped) instances toward pool target when pool_strategy=warm
- Pool tries to start warm instances before cold-launching new ones
- Remaining deficit is filled by createRunners (cold start)
- Scale-down will stop excess idle runners into warm pool after they run

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Test disabled/hot strategy returns empty
- Test starting and tagging warm instances
- Test failure handling (skip failed, cleanup DynamoDB)
- Test org-level fallback for repo-level owners
- Test multiple instance start up to count
- Test tag failure as non-fatal (best-effort)

Signed-off-by: Brend Smits <brend.smits@philips.com>
Scale-down eviction tests:
- Skip eviction when warm pool disabled
- Evict instances exceeding max age
- Evict instances exceeding max count
- Emit WarmPoolSize metric after eviction

Pool warm strategy tests:
- Count warm instances toward pool target
- Try warm instances before cold launching
- Skip cold launch when warm satisfies full top-up
- Don't count warm instances with hot strategy

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Add amiId field to WarmPoolEntry interface and DynamoDB storage
- Store current AMI ID (from SSM parameter) when stopping instances
- Evict warm instances with stale AMI during eviction cycle
- Add @aws-sdk/client-dynamodb to control-plane dependencies
- Pass AMI_ID_SSM_PARAMETER_NAME env var to scale-down lambda
- Grant scale-down IAM permission to read AMI SSM parameter

Signed-off-by: Brend Smits <brend.smits@philips.com>
Add findAndStartWarmRunners and warm-pool module mocks to
existing pool.test.ts to prevent failures from new imports.

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Verify DynamoDB table not created when disabled (default)
- Verify DynamoDB table created with correct schema when enabled
- Verify IAM policies attached to scale-down, scale-up, and pool roles
- Verify pool_strategy defaults to 'hot'
- Verify warm strategy + enabled config creates resources

Signed-off-by: Brend Smits <brend.smits@philips.com>
- Measure and emit start latency (ms) for warm instance starts
- Emit WarmPoolEvicted metric count during eviction cycles
- Use MetricUnit.Milliseconds for latency metric

Signed-off-by: Brend Smits <brend.smits@philips.com>
When pool_strategy=warm and new instances are cold-launched:
- Wait warmPoolReadyDelaySeconds (default 30s) after creation
- Re-check GitHub runner status for each new instance
- If runner picked up a job: leave running, tag ghr:warm-pool-grace-hit
- If runner is idle: stop instance and add to warm pool

This enables the pool to maintain warm (stopped) instances at zero
idle compute cost while giving jobs a chance to claim new runners.

Signed-off-by: Brend Smits <brend.smits@philips.com>
Signed-off-by: Brend Smits <brend.smits@philips.com>
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 1 package(s) with unknown licenses.
See the Details below.

License Issues

lambdas/functions/control-plane/package.json

PackageVersionLicenseIssue Type
@aws-sdk/client-dynamodb^3.1078.0NullUnknown License

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
npm/@aws-sdk/client-dynamodb ^3.1078.0 UnknownUnknown
npm/@aws-sdk/client-dynamodb 3.1078.0 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/core 3.974.26 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-env 3.972.52 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-http 3.972.54 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-ini 3.972.59 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-login 3.972.58 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-node 3.972.61 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-process 3.972.52 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-sso 3.972.58 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/credential-provider-web-identity 3.972.58 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/dynamodb-codec 3.973.26 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/endpoint-cache 3.972.8 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/middleware-endpoint-discovery 3.972.22 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/nested-clients 3.997.26 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/signature-v4-multi-region 3.996.38 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/token-providers 3.1078.0 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/types 3.973.15 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@aws-sdk/xml-builder 3.972.33 🟢 6.9
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Code-Review⚠️ 1Found 4/30 approved changesets -- score normalized to 1
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Token-Permissions🟢 5detected GitHub workflow tokens with excessive permissions
License🟢 10license file detected
Branch-Protection🟢 5branch protection is not maximal on development and all release branches
Signed-Releases⚠️ 0Project has not signed or included provenance with any releases.
Security-Policy🟢 10security policy file detected
Packaging🟢 10packaging workflow detected
SAST🟢 10SAST tool is run on all commits
Binary-Artifacts🟢 9binaries present in source code
Pinned-Dependencies🟢 8dependency not pinned by hash detected -- score normalized to 8
Fuzzing🟢 10project is fuzzed
npm/@smithy/core 3.29.0 UnknownUnknown
npm/@smithy/credential-provider-imds 4.4.5 UnknownUnknown
npm/@smithy/fetch-http-handler 5.6.2 UnknownUnknown
npm/@smithy/node-http-handler 4.9.2 UnknownUnknown
npm/@smithy/signature-v4 5.6.1 UnknownUnknown
npm/@smithy/types 4.15.1 UnknownUnknown
npm/mnemonist 0.38.3 🟢 3.2
Details
CheckScoreReason
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
Packaging⚠️ -1packaging workflow not detected
Code-Review🟢 3Found 10/30 approved changesets -- score normalized to 3
Maintained⚠️ 12 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Binary-Artifacts🟢 10no binaries found in the repo
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Security-Policy⚠️ 0security policy file not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Branch-Protection⚠️ 0branch protection not enabled on development/release branches
Signed-Releases⚠️ -1no releases found
SAST⚠️ 0SAST tool is not run on all commits -- score normalized to 0
npm/obliterator 1.6.1 UnknownUnknown

Scanned Files

  • lambdas/functions/control-plane/package.json
  • lambdas/yarn.lock

Comment thread lambdas/functions/control-plane/src/pool/pool-warm-strategy.test.ts Fixed
Comment thread lambdas/functions/control-plane/src/pool/pool-warm-strategy.test.ts Fixed
Comment thread lambdas/functions/control-plane/src/pool/pool.test.ts Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a “warm pool” lifecycle to the Terraform AWS GitHub Runner module so idle runners can be stopped (EBS-only cost) and later restarted quickly, instead of being terminated and cold-launched.

Changes:

  • Introduces warm_pool_config and pool_strategy inputs and wires them through root, runners, pool, and multi-runner modules.
  • Provisions a DynamoDB warm-pool state table plus IAM policies, and passes warm-pool env vars into scale-up/scale-down/pool lambdas.
  • Implements warm-pool stop/start and eviction logic in the control-plane lambdas, adds unit + Terraform tests, and documents the design (docs + ADRs).

Reviewed changes

Copilot reviewed 33 out of 34 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
variables.tf Adds root-level warm-pool inputs and warm-pool metrics toggle.
README.md Documents new inputs and updates instance allocation strategy wording.
modules/termination-watcher/termination/README.md Regenerates docs to include new IAM policy resource.
modules/termination-watcher/notification/README.md Regenerates docs to include new event rules/targets/permissions/policy resources.
modules/runners/warm-pool.tf Creates warm-pool DynamoDB table + IAM inline policies (new file).
modules/runners/variables.tf Adds warm-pool inputs and metrics toggle in runners module.
modules/runners/tests/warm-pool.tftest.hcl Adds Terraform test coverage for warm-pool resources and validation.
modules/runners/scale-up.tf Passes warm-pool env vars to scale-up lambda.
modules/runners/scale-down.tf Passes warm-pool env vars to scale-down lambda and adds SSM read policy attachment for AMI staleness logic.
modules/runners/README.md Regenerates runners module docs for warm-pool resources/inputs.
modules/runners/pool/variables.tf Extends pool submodule config object to include warm-pool settings.
modules/runners/pool/README.md Regenerates pool submodule docs for extended config schema.
modules/runners/pool/main.tf Passes warm-pool env vars to pool lambda.
modules/runners/pool.tf Wires warm-pool table/config into the pool submodule.
modules/runners/policies/lambda-warm-pool.json New IAM policy template for DynamoDB + EC2 stop/start/tag actions.
modules/multi-runner/variables.tf Adds warm-pool fields to multi-runner config type.
modules/multi-runner/runners.tf Passes warm-pool inputs through to each runners module instance.
modules/multi-runner/README.md Regenerates multi-runner docs to include warm-pool config fields.
mkdocs.yaml Adds warm-pool page to documentation nav.
main.tf Wires root warm-pool inputs into the runners module.
lambdas/yarn.lock Adds @aws-sdk/client-dynamodb dependency lock entries.
lambdas/functions/control-plane/src/scale-runners/scale-up.ts Adds warm instance lookup/start path before cold launching.
lambdas/functions/control-plane/src/scale-runners/scale-down.ts Stops idle instances into warm pool and adds warm eviction logic.
lambdas/functions/control-plane/src/scale-runners/scale-down-warm-pool.test.ts Adds unit tests for eviction behavior.
lambdas/functions/control-plane/src/scale-runners/find-and-start-warm-runners.test.ts Adds unit tests for warm start behavior.
lambdas/functions/control-plane/src/pool/pool.ts Updates pool logic to account for warm instances and implement warm-strategy grace period stop.
lambdas/functions/control-plane/src/pool/pool.test.ts Updates existing pool tests for new wiring/mocks.
lambdas/functions/control-plane/src/pool/pool-warm-strategy.test.ts Adds pool warm-strategy-specific unit tests.
lambdas/functions/control-plane/src/aws/warm-pool.ts New DynamoDB warm-pool state client + metric emitter.
lambdas/functions/control-plane/src/aws/runners.ts Adds EC2 start/stop helpers for warm pool.
lambdas/functions/control-plane/package.json Adds @aws-sdk/client-dynamodb dependency.
docs/warm-pool.md Adds feature documentation and configuration guide.
docs/adr/001-warm-pool-implementation-plan.md Adds detailed phased implementation plan ADR.
docs/adr/001-warm-pool-hibernation.md Adds warm-pool decision ADR and design rationale.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/runners/variables.tf
Comment thread modules/runners/warm-pool.tf Outdated
Comment thread lambdas/functions/control-plane/src/scale-runners/scale-up.ts
Comment thread lambdas/functions/control-plane/src/scale-runners/scale-down.ts
Comment thread lambdas/functions/control-plane/src/scale-runners/scale-down.ts
Comment thread lambdas/functions/control-plane/src/pool/pool.ts
Comment thread lambdas/functions/control-plane/src/pool/pool.ts
Comment thread lambdas/functions/control-plane/src/aws/warm-pool.ts Outdated
- Remove unused imports in test files (CodeQL warnings)
- Move check block to variable validation (TF >= 1.3 compat)
- Gate scale-up warm starts on warmPoolConfig.enabled only,
  not poolStrategy (scale-up should try warm starts regardless
  of pool lambda strategy)
- Wrap scale-down warm pool stop in try/catch with fallback
  to terminate on failure
- Include stopped instances in eviction owner lookup
- Add AMI ID to pool-created warm instances for staleness eviction
- Make removeFromWarmPool atomic with conditional delete to
  prevent concurrent scale-up race conditions
- Add test for concurrent claim scenario

Signed-off-by: Brend Smits <brend.smits@philips.com>
Cross-variable references in variable validation blocks require
Terraform 1.9+. The repo supports >= 1.3.0, so this breaks CI on
TF 1.5.6. The constraint (pool_strategy=warm requires enabled=true)
is documented in the variable description and enforced at runtime
by the lambda.

Signed-off-by: Brend Smits <brend.smits@philips.com>
@edersonbrilhante

Copy link
Copy Markdown
Contributor

Great idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants