Skip to content

Commit 91e89f5

Browse files
committed
fix(design): require explicit HTTP(S) scheme and bound array sizes for committee metadata fields
The shared urlPattern (website/repository) allowed non-HTTP schemes like javascript: or data: to pass validation since the scheme prefix was optional; make it mandatory. Also add MaxLength bounds on scope, deliverables, and key_dates arrays, matching the existing description/label size-bound convention, since these are persisted to NATS KV and indexed with no prior cap. Addresses PR #149 review feedback from Copilot and CodeRabbit. Jira: LFXV2-1709 Link: https://linuxfoundation.atlassian.net/browse/LFXV2-1709 Signed-off-by: Prabodh Chaudhari <pchaudhari@linuxfoundation.org>
1 parent ad0b7c8 commit 91e89f5

9 files changed

Lines changed: 469 additions & 272 deletions

File tree

cmd/committee-api/design/type.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,10 @@ func DescriptionAttribute() {
201201
})
202202
}
203203

204-
// urlPattern validates an optional-scheme URL (used by website and repository attributes).
205-
const urlPattern = `^(https?://)?[^\s/$.?#].[^\s]*$`
204+
// urlPattern validates an HTTP(S) URL (used by website and repository attributes).
205+
// The scheme is mandatory to reject non-HTTP schemes (e.g. javascript:, data:) that
206+
// would otherwise pass dsl.FormatURI as syntactically valid URIs.
207+
const urlPattern = `^https?://[^\s/$.?#][^\s]*$`
206208

207209
// WebsiteAttribute is the DSL attribute for committee website.
208210
func WebsiteAttribute() {
@@ -225,13 +227,21 @@ func RepositoryAttribute() {
225227
// ScopeAttribute is the DSL attribute for committee scope bullet points.
226228
func ScopeAttribute() {
227229
dsl.Attribute("scope", dsl.ArrayOf(dsl.String), "The scope of the committee, as a list of bullet points", func() {
230+
dsl.MaxLength(50)
231+
dsl.Elem(func() {
232+
dsl.MaxLength(500)
233+
})
228234
dsl.Example([]string{"Define governance for the project", "Review and approve major architectural changes"})
229235
})
230236
}
231237

232238
// DeliverablesAttribute is the DSL attribute for committee deliverables bullet points.
233239
func DeliverablesAttribute() {
234240
dsl.Attribute("deliverables", dsl.ArrayOf(dsl.String), "The deliverables of the committee, as a list of bullet points", func() {
241+
dsl.MaxLength(50)
242+
dsl.Elem(func() {
243+
dsl.MaxLength(500)
244+
})
235245
dsl.Example([]string{"Quarterly technical roadmap", "Annual governance review"})
236246
})
237247
}
@@ -256,6 +266,7 @@ var KeyDateType = dsl.Type("key-date", func() {
256266
// KeyDatesAttribute is the DSL attribute for a committee's key-dates timeline.
257267
func KeyDatesAttribute() {
258268
dsl.Attribute("key_dates", dsl.ArrayOf(KeyDateType), "Timeline of important dates for the committee", func() {
269+
dsl.MaxLength(50)
259270
dsl.Example([]map[string]interface{}{
260271
{"date": "2026-04", "label": "Charter renewal"},
261272
})
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright The Linux Foundation and each contributor to LFX.
2+
// SPDX-License-Identifier: MIT
3+
4+
package design
5+
6+
import (
7+
"regexp"
8+
"testing"
9+
)
10+
11+
func TestURLPattern(t *testing.T) {
12+
re := regexp.MustCompile(urlPattern)
13+
14+
tests := []struct {
15+
name string
16+
value string
17+
want bool
18+
}{
19+
{"https URL", "https://github.com/example/repo", true},
20+
{"http URL", "http://committee.example.org", true},
21+
{"javascript scheme rejected", "javascript:alert(1)", false},
22+
{"data scheme rejected", "data:text/html,<script>alert(1)</script>", false},
23+
{"file scheme rejected", "file:///etc/passwd", false},
24+
{"schemeless domain rejected", "committee.example.org", false},
25+
{"empty string rejected", "", false},
26+
}
27+
28+
for _, tt := range tests {
29+
t.Run(tt.name, func(t *testing.T) {
30+
if got := re.MatchString(tt.value); got != tt.want {
31+
t.Errorf("urlPattern.MatchString(%q) = %v, want %v", tt.value, got, tt.want)
32+
}
33+
})
34+
}
35+
}

gen/http/committee_service/client/cli.go

Lines changed: 42 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gen/http/committee_service/client/types.go

Lines changed: 84 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gen/http/committee_service/server/types.go

Lines changed: 42 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gen/http/openapi.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)