The NetworkPortsModule cached EC2 NACLs and Security Groups in two
per-region maps. The cache lookup read the maps without holding a
lock while the cache population path took a write lock, producing a
"concurrent map read and map write" runtime panic when multiple
region goroutines hit the cache check concurrently. The panic
reproduced reliably in low-density AWS accounts where every region
goroutine raced through the cache check at the same instant.
Take the read lock on the cache fast-path in both
getEC2NACLsPerRegion and getEC2SecurityGroupsPerRegion. Move
naclsMutex and securityGroupsMutex from package-level vars onto the
module struct so concurrent module instances stop serializing on
each other's locks.
Convert CommandCounter from plain int fields with naked ++/-- to
int64 fields with Incr/Decr/Load methods that use atomic.AddInt64
and atomic.LoadInt64 internally. Worker goroutines and the spinner
goroutine were updating and reading the same counters without
synchronization, producing torn integer writes that could show as
off-by-one progress in the spinner. Plain int64 storage keeps the
struct copyable so existing constructors and helpers that take
modules by value continue to vet-clean.
Add TestNetworkPortsCacheConcurrentAccess as a regression test.
With the read lock removed, "go test -race" reports the
mapaccess2_faststr read racing the locked write; with the fix in
place the test passes.
- actions/checkout v4 -> v6
- actions/setup-go v4 -> v5
- go-version ^1.20 -> ^1.25
- Replace abandoned marvinpinto/action-automatic-releases with
softprops/action-gh-release v2
Node.js 20 actions are deprecated and will be forced to Node 24
starting June 2, 2026, and removed September 16, 2026.
The pmapperCommand in runAllChecksCommand was missing the
PmapperDataBasePath parameter, causing --pmapper-data-basepath to be
ignored for the pmapper module when running all-checks. (Fixes#105)
The instances module had a race condition where role analysis ran before
the receiver goroutine finished collecting all MappedInstances. This
caused IsAdminRole and CanPrivEscToAdmin columns to appear empty in
all-checks despite pmapper data being available. Fixed by signaling
the receiver to stop and waiting for it to drain before running role
analysis.
Version bumped to 2.0.4.
The EC2 user data InstancesModule in runAllChecksCommand was not receiving
the PmapperDataBasePath parameter, causing the --pmapper-data-basepath flag
to be ignored when running all-checks.
Fix: Add PmapperDataBasePath: PmapperDataBasePath to the ec2UserData struct
initialization in runAllChecksCommand.
awsservicemap v1.1.0 switched to URL-based service slugs, breaking all
commands that used the old identifiers. Affected slugs and their fixes:
secretsmanager -> secrets-manager (resource-trusts, inventory)
ssm -> systems-manager (inventory)
elb -> elasticloadbalancing (endpoints, inventory, network-ports)
es -> opensearch-service (endpoints, inventory, resource-trusts)
mq -> amazon-mq (endpoints, inventory)
stepfunctions -> step-functions (inventory)
sagemaker -> sagemaker-ai (env-vars)
clouddirectory -> directoryservice (directory-services)
kinesis -> streams (inventory)
lightsail -> amazonlightsail.com (endpoints, env-vars, network-ports)
Each mismatch caused IsServiceInRegion to return false for all regions,
silently skipping enumeration of that service entirely.
awsservicemap v1.1.0 changed to a URL-based service identification format.
The secrets module was passing old-style slugs ("secretsmanager", "ssm") to
IsServiceInRegion, which never matched the new URL-derived slugs
("secrets-manager", "systems-manager"). This caused 0 tasks to be queued
and no secrets to be returned despite secrets existing in the account.