Skip to content

fix: parse day and fractional-second components in FromTimeSpan (cherry-pick of #435) - #452

Closed
NickJosevski wants to merge 1 commit into
mainfrom
fix/timespan-parsing
Closed

fix: parse day and fractional-second components in FromTimeSpan (cherry-pick of #435)#452
NickJosevski wants to merge 1 commit into
mainfrom
fix/timespan-parsing

Conversation

@NickJosevski

Copy link
Copy Markdown
Contributor

Cherry-pick of #435 by @Scott-Emberson, re-hosted on a branch in this repo solely so CI can run. Authorship is preserved on the commit — this is a mechanical move, not a rewrite, and the work and the analysis are entirely Scott's.

Fork PRs cannot satisfy the required test check: integration-tests.yml needs secrets.DB_IMAGE_SA_PASSWORD, OD_IMAGE_ADMIN_API_KEY and OCTOPUS_SERVER_BASE64_LICENSE, and GitHub withholds secrets from pull_request runs originating on a fork, so the job dies at Initialize containers before any Go executes. #435 is red for that reason and no other.

The bug

FromTimeSpan read the day component from timeSpan[0:0] — always the empty string — so every value carrying days parsed to zero. Fixed offsets also assumed a single-digit day, fractional seconds were dropped, and an empty string panicked on a slice bound. It is duplicated verbatim in pkg/machines and pkg/machinepolicies; this fixes both.

Running main's parser against this one on the same inputs:

input correct main today this PR
00:05:00 5m0s 5m0s 5m0s
01:30:00 1h30m0s 1h30m0s 1h30m0s
1.00:00:00 24h0m0s 0s 24h0m0s
7.12:30:00 180h30m0s 12h30m0s 180h30m0s
07.12:30:00 180h30m0s 0s 180h30m0s
10.00:00:00 240h0m0s 0s 240h0m0s
00:00:00.5000000 500ms 0s 500ms
1.02:03:04.5000000 26h3m4.5s 2h3m4s 26h3m4.5s
"" 0s panic 0s

Every day-bearing value was silently wrong rather than failing loudly. Plain hh:mm:ss is identical before and after, so nothing that works today regresses.

Blast radius

Read path only. ToTimeSpan, which produces what gets sent to the server, is untouched. All 14 in-repo callers of FromTimeSpan sit inside UnmarshalJSON on machine policy, cleanup policy and health check policy. It also closes a quiet data-loss path: today you can read a policy, write it back unchanged, and send a day-scale interval out as zero.

Two notes for the release

  1. Negative time spans remain wrong, in both directions — pre-existing, not touched here, and arguably never supported:
    FromTimeSpan("-1.02:03:04") = -21h56m56s   // .NET means -26h3m4s
    FromTimeSpan("-00:05:00")   = 5m0s         // sign dropped entirely
    ToTimeSpan(-26h3m4s)        = "-1.-2:-3:-4"
    
  2. This changes values consumers already read. Anyone getting 0s for these fields starts getting the true duration, which may surface as a one-off Terraform plan on machine policy timeouts. There is no CHANGELOG.md and goreleaser builds notes from commit subjects only, so this needs a note pasted onto the GitHub Release at tag time. Wording is in a comment on fix: parse day and fractional-second components in FromTimeSpan (changes parsed values) #435.

Once this merges

Close #435 pointing here, so Scott gets the credit and knows it wasn't rejected.

FromTimeSpan read the time span fields at fixed offsets and took the day
component from timeSpan[0:0], which is always the empty string. Every value
carrying a day component therefore parsed to zero, including "1.00:00:00" —
the interval on the default machine policy — and any fractional seconds were
dropped. An empty string panicked on a slice bound.

Parse the components by separator instead. The day and fractional-second
parts are both optional, and the server does not pad the day component to a
fixed width, so offsets cannot be assumed. Malformed input now yields a zero
duration rather than a panic.

The existing tests only logged their results and asserted nothing, which is
why this went unnoticed; they now assert, and every case they already covered
was returning zero.

Closes #434

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 5d7ef5e)
Co-authored-by: Scott Emberson <8268155+Scott-Emberson@users.noreply.github.com>
@NickJosevski

Copy link
Copy Markdown
Contributor Author

Superseded by #458, merged 2026-08-23.

This was a mechanical re-host of #435 so CI could run on it. It went stale while it waited: #458 fixed the same bug independently, rewriting FromTimeSpan in both pkg/machines and pkg/machinepolicies.

Rebasing onto main conflicts in all four files, and resolving it toward this branch would be a regression rather than a fix:

input main (#458) this branch
-01:30:00 -1h30m0s -30m0s
-1.02:03:04 -26h3m4s -21h56m56s
00:00:00.1234567890123 123.4567ms -136.396µs
1.00:00:00, 7.12:30:00, 00:00:00.5000000, "" correct correct

Negative time spans are the ones this PR's own description flagged as remaining wrong; #458 handles them. The pow10 scaling here also overflows int64 past nine fraction digits and flips negative, where #458 truncates to seven ticks. Every assertion in this branch's tests passes against main unchanged, so there is no bug left to fix.

The additive test coverage is carried forward in #479, with @Scott-Emberson as co-author. #434 and #435 are closed against #458.

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.

2 participants