Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
ee17fa2
LWLP-35: create db schema for clearinghouse ui
TenSt Aug 14, 2026
e8e00c8
Merge branch 'pr/1635' into LWLP-5-Lightwell-Network-API
etsien Aug 18, 2026
f0048ec
build out phase 1: advisories, packages, repositories, package-versio…
etsien Aug 18, 2026
212ca7b
Merge branch 'main' into LWLP-5-Lightwell-Network-API
etsien Aug 19, 2026
e990645
Update .gitignore
etsien Aug 24, 2026
3373e92
v2 of API buildout Phase 1
etsien Aug 24, 2026
d18fec3
add tests
etsien Aug 24, 2026
bcdc0d2
Create advisories.sql.go
etsien Aug 24, 2026
ec38125
Merge branch 'main' into LWLP-5-Lightwell-Network-API
etsien Aug 24, 2026
a71bf04
revert docs changes
etsien Aug 24, 2026
0d66a2f
Revert "revert docs changes"
etsien Aug 24, 2026
e79f887
update docs and api
etsien Aug 25, 2026
8827f3f
re-add tests
etsien Aug 25, 2026
cc7b447
update migrations
etsien Aug 25, 2026
949fedd
bugfix
etsien Aug 25, 2026
9501f5d
Update migrations.latest
etsien Aug 25, 2026
7e92db7
Update store_test.go
etsien Aug 25, 2026
38da107
LWLP-5: add Lightwell advisory schema, sqlc queries, and store tests
etsien Aug 25, 2026
7344968
LWLP-5: add Lightwell advisories and packages API
etsien Aug 25, 2026
d6351b9
LWLP-5: regenerate OpenAPI spec for Lightwell endpoints
etsien Aug 25, 2026
5d2ed76
Merge branch 'LWLP-5-Lightwell-Network-API' of https://github.com/ets…
etsien Aug 25, 2026
0b5baac
LWLP-5: add Lightwell advisory schema, sqlc queries, and store tests
etsien Aug 25, 2026
5e7a921
LWLP-5: add Lightwell advisories and packages API
etsien Aug 25, 2026
32508fa
LWLP-5: regenerate OpenAPI spec for Lightwell endpoints
etsien Aug 25, 2026
f2c37d9
Merge branch 'LWLP-5-Lightwell-Network-API' of https://github.com/ets…
etsien Aug 25, 2026
500fa1c
revert and delete duplicates sql files
etsien Aug 26, 2026
8aa9d3d
update calls to use DAO package
etsien Aug 26, 2026
fe1c192
LWLP-5: add Lightwell advisory schema, sqlc queries, and store tests
etsien Aug 26, 2026
57cb035
LWLP-5: add Lightwell advisories and packages API via DAO layer
etsien Aug 26, 2026
7dad8d6
LWLP-5: regenerate OpenAPI spec for Lightwell endpoints
etsien Aug 26, 2026
e3e7cf4
LWLP-5: regenerate mocks
etsien Aug 26, 2026
8148581
LWLP-5: fix spec deviations and test isolation from merge resolution
etsien Aug 26, 2026
dfbaaff
Merge remote branch origin/LWLP-5-Lightwell-Network-API
etsien Aug 26, 2026
f9d9539
LWLP-5: resolve merge conflict with upstream main
etsien Aug 26, 2026
e939ceb
LWLP-5: align with upstream main changes
etsien Aug 26, 2026
b9413dd
more rebase fixes
etsien Aug 27, 2026
8923b2a
remove repeated call
etsien Aug 27, 2026
e7f7514
fix swagger annotation
etsien Aug 27, 2026
3b1a2e6
add the v2 API spec
etsien Aug 27, 2026
a4b8f6d
fix linting issues
etsien Aug 27, 2026
f749048
update api docs
etsien Aug 27, 2026
42f813b
Update interfaces.go
etsien Aug 27, 2026
872eed6
rename template
etsien Aug 27, 2026
96fb90f
Merge branch 'main' into LWLP-5-Lightwell-Network-API
etsien Aug 27, 2026
7214c79
bring back accidentally removed rebased stuff
etsien Sep 2, 2026
2215df8
reuse existing counts, remove redundant fields
etsien Sep 2, 2026
2d1bfb4
regenerate docs
etsien Sep 2, 2026
3c375a4
Merge upstream/main into LWLP-5-Lightwell-Network-API
etsien Sep 2, 2026
40d31f4
fix: rename advisory migration to follow upstream timestamp
etsien Sep 2, 2026
cfab2a2
Create handler-test-patterns.mdc
etsien Sep 2, 2026
168e52e
add properties to PackageVersion
etsien Sep 2, 2026
349cb8c
add PURL and coordinate builders, adjust CVE filters to use repo name…
etsien Sep 2, 2026
f11d6e9
add tests
etsien Sep 2, 2026
de0e4aa
Merge branch 'main' into add-purl-and-coordinates-to-package_versions…
etsien Sep 2, 2026
228baa5
add re-generated docs
etsien Sep 3, 2026
1a333f8
Merge branch 'add-purl-and-coordinates-to-package_versions-endpoint' …
etsien Sep 3, 2026
631b703
Merge upstream/main into add-purl-and-coordinates-to-package_versions…
etsien Sep 10, 2026
a3eac03
regenerate docs
etsien Sep 10, 2026
4333b10
fix: remove duplicate severity migration superseded by upstream
etsien Sep 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5471,6 +5471,9 @@ const docTemplate = `{
"api.LightwellPackageVersionResponse": {
"type": "object",
"properties": {
"coordinates": {
"type": "string"
},
"created_at": {
"type": "string"
},
Expand All @@ -5483,6 +5486,9 @@ const docTemplate = `{
"name": {
"type": "string"
},
"purl": {
"type": "string"
},
"release": {
"type": "string"
},
Expand Down
6 changes: 6 additions & 0 deletions api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@
},
"api.LightwellPackageVersionResponse": {
"properties": {
"coordinates": {
"type": "string"
},
"created_at": {
"type": "string"
},
Expand All @@ -482,6 +485,9 @@
"name": {
"type": "string"
},
"purl": {
"type": "string"
},
"release": {
"type": "string"
},
Expand Down
2 changes: 2 additions & 0 deletions pkg/api/lightwell_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type LightwellPackageVersionResponse struct {
RepositoryUUID string `json:"repository_uuid"`
Release string `json:"release,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
Purl string `json:"purl"`
Coordinates string `json:"coordinates"`
}

// LightwellPackageVersionCollectionResponse is a paginated collection of cross-repo package versions.
Expand Down
7 changes: 7 additions & 0 deletions pkg/handler/lightwell_advisories.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func RegisterLightwellAdvisoryRoutes(engine *echo.Group, daoReg *dao.DaoRegistry
FeatureServiceClient: *fsClient,
}
addRepoRoute(engine, http.MethodGet, "/lightwell/advisories", h.list, rbac.RbacVerbRead)
addRepoRoute(engine, http.MethodGet, "/lightwell/repositories/:repository_name/advisories", h.listRepoAdvisories, rbac.RbacVerbRead)
}
Comment on lines +27 to 28

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this route got leftover from a rebase?


// listLightwellAdvisories godoc
Expand Down Expand Up @@ -105,3 +106,9 @@ func parseLightwellAdvisoryFilters(c echo.Context) api.LightwellAdvisoryFilterDa
BindError()
return filters
}

func (h *LightwellAdvisoryHandler) listRepoAdvisories(c echo.Context) error {
repoName := c.Param("repository_name")
c.QueryParams().Set("repository", repoName)
return h.list(c)
}
39 changes: 39 additions & 0 deletions pkg/handler/lightwell_advisories_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,45 @@ func (s *LightwellAdvisorySuite) TestListAdvisoriesFilterByRepoName() {
assert.Equal(t, http.StatusOK, code)
}

func (s *LightwellAdvisorySuite) TestNestedRepoAdvisoriesAlias() {
t := s.T()
s.stubLightwellAccess()

data := []api.LightwellAdvisoryResponse{
{
AdvisoryID: "CVE-2024-5678",
Severity: "important",
Details: "Test advisory via nested route",
ReferenceURLs: []string{},
PackageName: "spring-core",
FixedVersions: []string{"5.3.18.rhlw-00003"},
Repository: "java-remediated",
},
}

s.reg.LightwellAdvisory.On("ListAdvisories", test.MockCtx(), mock.MatchedBy(func(opts dao.ListLightwellAdvisoriesOptions) bool {
return opts.RepoName != nil && *opts.RepoName == "java-remediated" &&
len(opts.EntitledFeatures) == 1 && opts.EntitledFeatures[0] == "lightwell-network"
})).Return(data, int64(1), nil)

path := fmt.Sprintf("%s/lightwell/repositories/java-remediated/advisories", api.FullRootPath())
req := httptest.NewRequest(http.MethodGet, path, nil)
req.Header.Set(api.IdentityHeader, test_handler.EncodedIdentity(t))

code, body, err := s.serveRouter(req)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, code)

var resp api.LightwellAdvisoryCollectionResponse
err = json.Unmarshal(body, &resp)
require.NoError(t, err)

assert.Equal(t, int64(1), resp.Meta.Count)
assert.Len(t, resp.Data, 1)
assert.Equal(t, "CVE-2024-5678", resp.Data[0].AdvisoryID)
assert.Equal(t, "java-remediated", resp.Data[0].Repository)
}

func (s *LightwellAdvisorySuite) TestListAdvisoriesNoFeatureAccess() {
t := s.T()

Expand Down
88 changes: 75 additions & 13 deletions pkg/handler/lightwell_packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func RegisterLightwellPackageRoutes(engine *echo.Group, daoReg *dao.DaoRegistry,
}
addRepoRoute(engine, http.MethodGet, "/lightwell/packages", h.listPackages, rbac.RbacVerbRead)
addRepoRoute(engine, http.MethodGet, "/lightwell/package_versions", h.listPackageVersions, rbac.RbacVerbRead)
addRepoRoute(engine, http.MethodGet, "/lightwell/repositories/:repository_name/packages", h.listRepoPackages, rbac.RbacVerbRead)
addRepoRoute(engine, http.MethodGet, "/lightwell/repositories/:repository_name/package_versions", h.listRepoPackageVersions, rbac.RbacVerbRead)
Comment on lines +37 to +38

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

}

// listLightwellPackages godoc
Expand Down Expand Up @@ -221,7 +223,6 @@ func (h *LightwellPackagesHandler) fetchPackagesFromRepo(ctx context.Context, re
return nil, err
}

// Fetch all packages from this repo (no server-side pagination — small datasets)
pageOpts := tangy.PageOptions{Offset: 0, Limit: MaxLimit}

switch repo.ContentType {
Expand Down Expand Up @@ -355,19 +356,22 @@ func (h *LightwellPackagesHandler) filterVersionsByResolvingCve(ctx context.Cont
return nil, err
}

fixedSet := make(map[string]map[string]bool)
type repoPackage struct{ repo, name string }
fixedSet := make(map[repoPackage]map[string]bool)
for _, m := range matches {
if fixedSet[m.PackageName] == nil {
fixedSet[m.PackageName] = make(map[string]bool)
key := repoPackage{repo: m.RepoName, name: m.PackageName}
if fixedSet[key] == nil {
fixedSet[key] = make(map[string]bool)
}
for _, v := range m.FixedVersions {
fixedSet[m.PackageName][v] = true
fixedSet[key][v] = true
}
}

var result []api.LightwellPackageVersionResponse
for _, item := range items {
if versions, ok := fixedSet[item.Name]; ok && versions[item.Version] {
key := repoPackage{repo: item.Repository, name: item.Name}
if versions, ok := fixedSet[key]; ok && versions[item.Version] {
result = append(result, item)
}
}
Expand All @@ -382,27 +386,65 @@ func (h *LightwellPackagesHandler) filterVersionsByVulnerableCve(ctx context.Con
return nil, err
}

affectedPackages := make(map[string]bool)
fixedSet := make(map[string]map[string]bool)
type repoPackage struct{ repo, name string }
affectedPackages := make(map[repoPackage]bool)
fixedSet := make(map[repoPackage]map[string]bool)
for _, m := range matches {
affectedPackages[m.PackageName] = true
if fixedSet[m.PackageName] == nil {
fixedSet[m.PackageName] = make(map[string]bool)
key := repoPackage{repo: m.RepoName, name: m.PackageName}
affectedPackages[key] = true
if fixedSet[key] == nil {
fixedSet[key] = make(map[string]bool)
}
for _, v := range m.FixedVersions {
fixedSet[m.PackageName][v] = true
fixedSet[key][v] = true
}
}

var result []api.LightwellPackageVersionResponse
for _, item := range items {
if affectedPackages[item.Name] && !fixedSet[item.Name][item.Version] {
key := repoPackage{repo: item.Repository, name: item.Name}
if affectedPackages[key] && !fixedSet[key][item.Version] {
result = append(result, item)
}
}
return result, nil
}

// --- PURL / coordinate builders ---

func buildPURL(contentType, group, name, version string) string {
switch contentType {
case config.ContentTypeMaven:
return fmt.Sprintf("pkg:maven/%s/%s@%s", group, name, version)
case config.ContentTypePython:
return fmt.Sprintf("pkg:pypi/%s@%s", name, version)
case config.ContentTypeNpm:
if group == "-" || group == "" {
return fmt.Sprintf("pkg:npm/%s@%s", name, version)
}
scope := strings.TrimPrefix(group, "@")
return fmt.Sprintf("pkg:npm/%%40%s/%s@%s", scope, name, version)
default:
return ""
}
}

func buildCoordinates(contentType, group, name string) string {
switch contentType {
case config.ContentTypeMaven:
return fmt.Sprintf("%s:%s", group, name)
case config.ContentTypePython:
return name
case config.ContentTypeNpm:
if group == "-" || group == "" {
return name
}
return fmt.Sprintf("%s/%s", group, name)
default:
return ""
}
}

// --- mapping helpers ---

func mapMavenToLightwellPackages(resp tangy.MavenPackageListResponse, repo api.RepositoryResponse) []api.LightwellPackageResponse {
Expand Down Expand Up @@ -477,6 +519,8 @@ func expandMavenVersions(resp tangy.MavenPackageListResponse, repo api.Repositor
Ecosystem: config.ContentTypeMaven,
Repository: repo.Name,
RepositoryUUID: repo.UUID,
Purl: buildPURL(config.ContentTypeMaven, item.GroupID, item.ArtifactID, v),
Coordinates: buildCoordinates(config.ContentTypeMaven, item.GroupID, item.ArtifactID),
}
if rel, ok := relMap[v]; ok {
ver.Release = rel.Release
Expand All @@ -499,6 +543,8 @@ func expandPythonVersions(resp tangy.PythonPackageListResponse, repo api.Reposit
Ecosystem: config.ContentTypePython,
Repository: repo.Name,
RepositoryUUID: repo.UUID,
Purl: buildPURL(config.ContentTypePython, "", item.NameNormalized, v),
Coordinates: buildCoordinates(config.ContentTypePython, "", item.NameNormalized),
}
if info, ok := verMap[v]; ok {
ver.CreatedAt = info.CreatedAt
Expand All @@ -522,6 +568,8 @@ func expandNpmVersions(resp tangy.NpmPackageListResponse, repo api.RepositoryRes
Ecosystem: config.ContentTypeNpm,
Repository: repo.Name,
RepositoryUUID: repo.UUID,
Purl: buildPURL(config.ContentTypeNpm, scope, name, v),
Coordinates: buildCoordinates(config.ContentTypeNpm, scope, name),
}
if info, ok := verMap[v]; ok {
ver.CreatedAt = info.CreatedAt
Expand Down Expand Up @@ -641,6 +689,20 @@ func npmVersionMap(versions []tangy.NpmVersionInfo) map[string]versionCreatedAt
return m
}

// --- nested repo-scoped alias handlers ---

func (h *LightwellPackagesHandler) listRepoPackages(c echo.Context) error {
repoName := c.Param("repository_name")
c.QueryParams().Set("repository", repoName)
return h.listPackages(c)
}

func (h *LightwellPackagesHandler) listRepoPackageVersions(c echo.Context) error {
repoName := c.Param("repository_name")
c.QueryParams().Set("repository", repoName)
return h.listPackageVersions(c)
}

// --- sort helpers ---

func sortLightwellPackages(items []api.LightwellPackageResponse, sortBy string) {
Expand Down
Loading
Loading