Skip to content

fix(api): drop a sub-1MB numeric mem_limit instead of reading it as unlimited - #466

Open
shani-singh1 wants to merge 1 commit into
oblien:mainfrom
shani-singh1:fix/compose-memory-sub-mb-unlimited
Open

fix(api): drop a sub-1MB numeric mem_limit instead of reading it as unlimited#466
shani-singh1 wants to merge 1 commit into
oblien:mainfrom
shani-singh1:fix/compose-memory-sub-mb-unlimited

Conversation

@shani-singh1

Copy link
Copy Markdown

Problem

parseComposeMemory (apps/api/src/lib/compose-parser.ts) parses a service's mem_limit / deploy.resources.limits.memory to MB. The string path already refuses a value that rounds below 1 MB (mb >= 1 ? … : undefined), but the number path did not:

// number path (before)
return raw > 0 ? Math.floor(raw / (1024 * 1024)) : undefined;

Math.floor(bytes / 1MB) is 0 for anything under a megabyte, so the two paths disagree for the same byte count:

parseComposeMemory(512)     // 0          parseComposeMemory("512")     // undefined
parseComposeMemory(1048575) // 0          parseComposeMemory("1048575") // undefined

0 is not inert here. In packages/core/src/resources.ts, UNLIMITED_RESOURCES is { memoryMb: 0, … } and hasMemoryLimit returns false for memoryMb: 0, and parseServiceResources keeps memoryMb: 0 (it only drops undefined). So a service written as:

services:
  api:
    image: nginx
    mem_limit: 512        # a bare YAML number → 512 *bytes*; almost always a typo for 512m

parses to no memory limit at all instead of a cap. That's the exact "a malformed limit must not silently become a tiny cap" failure this parser's own doc-comment and the #333 resource-limit tests exist to prevent — here it's worse, silently becoming unlimited.

Fix

Apply the same sub-1MB guard on the number path so it agrees with the string path:

const mb = raw / (1024 * 1024);
return mb >= 1 ? Math.floor(mb) : undefined;

Values ≥ 1 MB are unchanged — the existing bare-bytes case mem_limit: 1073741824 → 1024 MB still passes, as do all suffix spellings and the swarm form. Only sub-1MB numeric byte values change (0undefined), which then drops out of parseServiceResources instead of masquerading as unlimited.

Tests

Added to the existing "service resource limits" block:

expect(mem("512")).toBeUndefined();      // 512 bytes → <1 MB
expect(mem("1048575")).toBeUndefined();  // one byte under 1 MB
expect(mem("1048576")).toBe(1);          // exactly 1 MB still parses

Verified against the function logic: before the fix 512/1048575 return 0; after, they return undefined (matching the string path), while every value ≥ 1 MB (incl. the pinned 1073741824 → 1024) is unchanged.

…nlimited

`parseComposeMemory`'s string path already refuses a value that rounds below
1 MB (`mb >= 1 ? … : undefined`), but the number path did not — it returned
`Math.floor(bytes / 1MB)`, which is `0` for anything under a megabyte:

  parseComposeMemory(512)     -> 0          parseComposeMemory("512")     -> undefined
  parseComposeMemory(1048575) -> 0          parseComposeMemory("1048575") -> undefined

`0` is not inert. Downstream, `memoryMb: 0` is UNLIMITED_RESOURCES and
`hasMemoryLimit` returns false for it (packages/core/resources.ts), and
`parseServiceResources` keeps `memoryMb: 0` (it only drops `undefined`). So a
service written as `mem_limit: 512` — almost always a typo for `512m` — parses
to *no memory limit at all* instead of a cap. That is the exact "a malformed
limit must not silently become a tiny cap" failure this parser's own doc-comment
and the oblien#333 tests set out to prevent; here it's worse, becoming no cap.

Apply the same sub-1MB guard on the number path so it agrees with the string
path. Values >= 1 MB are unchanged (e.g. the bare-bytes `1073741824` -> 1024 MB
case stays). Added regression tests.
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.

1 participant