mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
fix(deadline): reject day/month dates that read differently by locale
--deadline 03/04/2026 was silently parsed as March 4. Numeric dates such as 03/04/2026 or 15.01.2028 are now refused with "the order of day and month is ambiguous; use YYYY-MM-DD", and the error for other invalid values no longer suggests clearing on issue create. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
2 files changed
+20
-2
No files matched your search
@@ -5,6 +5,8 @@ package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -12,18 +14,25 @@ import (
|
||||
"github.com/araddon/dateparse"
|
||||
)
|
||||
|
||||
// numericDate matches dates such as 03/04/2026, which read as March 4 in the US and April 3
|
||||
// elsewhere.
|
||||
var numericDate = regexp.MustCompile(`^\d{1,2}[/.]\d{1,2}[/.]\d{2,4}$`)
|
||||
|
||||
// parseDeadline parses a --deadline value; an empty value requests clearing.
|
||||
// Supplied timezone offsets are kept and Unix timestamps are UTC.
|
||||
func parseDeadline(value string) (*time.Time, *bool, error) {
|
||||
if value == "" {
|
||||
return nil, new(true), nil
|
||||
}
|
||||
if numericDate.MatchString(value) {
|
||||
return nil, nil, clierr.Wrap(clierr.Usage, fmt.Errorf("invalid --deadline %q: the order of day and month is ambiguous; use YYYY-MM-DD", value))
|
||||
}
|
||||
date, err := dateparse.ParseAny(value)
|
||||
if _, numericError := strconv.ParseInt(value, 10, 64); numericError == nil {
|
||||
date = date.UTC()
|
||||
}
|
||||
if err != nil || date.IsZero() || date.Unix() == 0 || date.Year() < 1 || date.Year() > 9999 {
|
||||
return nil, nil, clierr.Wrap(clierr.Usage, errors.New("invalid --deadline; use YYYY-MM-DD, RFC3339, a Unix timestamp, or an empty value to clear"))
|
||||
return nil, nil, clierr.Wrap(clierr.Usage, errors.New("invalid --deadline; use YYYY-MM-DD, RFC3339 or a Unix timestamp"))
|
||||
}
|
||||
return &date, nil, nil
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@@ -16,7 +17,7 @@ func TestDeadlineInputAndExplicitClearing(t *testing.T) {
|
||||
for _, tc := range []struct{ value, payload string }{
|
||||
{"2028-01-15", `{"due_date":"2028-01-15T00:00:00Z"}`},
|
||||
{"2028-01-15T00:30:00+02:00", `{"due_date":"2028-01-15T00:30:00+02:00"}`},
|
||||
{"01/15/2028", `{"due_date":"2028-01-15T00:00:00Z"}`},
|
||||
{"Jan 15 2028", `{"due_date":"2028-01-15T00:00:00Z"}`},
|
||||
{"1704067200000", `{"due_date":"2024-01-01T00:00:00Z"}`},
|
||||
{"1704067200", `{"due_date":"2024-01-01T00:00:00Z"}`},
|
||||
{"", `{"unset_due_date":true}`},
|
||||
@@ -41,6 +42,14 @@ func TestDeadlineInputAndExplicitClearing(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAmbiguousNumericDeadlinesAreRejected(t *testing.T) {
|
||||
for _, value := range []string{"03/04/2026", "04/03/2026", "01/15/2028", "15.01.2028", "3/4/26"} {
|
||||
for _, command := range [][]string{{"issue", "edit", "1"}, {"issue", "create", "--title", "x"}, {"milestone", "create", "--title", "x"}} {
|
||||
requireUsageBeforeRequests(t, fmt.Sprintf("invalid --deadline %q: the order of day and month is ambiguous; use YYYY-MM-DD", value), append(command, "--deadline="+value)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidDeadlineBeforeInputCollectionOrNetwork(t *testing.T) {
|
||||
for _, value := range []string{"bad", "2026-02-30", "0", "not-a-timestamp", "999999999999999999999999999999999999"} {
|
||||
for _, command := range [][]string{{"issue", "edit", "1"}, {"pr", "edit", "1", "--add-reviewers=alice"}, {"issue", "create"}, {"pr", "create"}} {
|
||||
|
||||
Reference in new issue
Block a user