all: refactor report.New to take options

Change-Id: I39aa1b2a34d6b6dc65ac1bd30d0336016643c86e
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/583776
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/cmd/vulnreport/create.go b/cmd/vulnreport/create.go
index 8dabeca..9b30192 100644
--- a/cmd/vulnreport/create.go
+++ b/cmd/vulnreport/create.go
@@ -234,10 +234,12 @@
 		src = report.Original()
 	}
 
-	r := report.New(src, id, modulePath, pc)
-
-	// Ensure all source aliases are added to the report.
-	r.AddAliases(aliases)
+	r := report.New(src, pc,
+		report.WithGoID(id),
+		report.WithModulePath(modulePath),
+		report.WithAliases(aliases),
+		report.WithCreated(time.Now()),
+	)
 
 	// Find any additional aliases referenced by the source aliases.
 	addMissingAliases(ctx, r, gc)
@@ -265,11 +267,6 @@
 		}
 	}
 
-	if r.SourceMeta != nil {
-		now := time.Now()
-		r.SourceMeta.Created = &now
-	}
-
 	return r
 }
 
diff --git a/internal/genericosv/report_test.go b/internal/genericosv/report_test.go
index 4e410e4..32529aa 100644
--- a/internal/genericosv/report_test.go
+++ b/internal/genericosv/report_test.go
@@ -52,8 +52,7 @@
 				t.Fatal(err)
 			}
 
-			modulePath := "" // ignored
-			got := report.New(osv, "GO-TEST-ID", modulePath, pc)
+			got := report.New(osv, pc)
 			// Keep record of what lints would apply to each generated report.
 			got.LintAsNotes(pc)
 
diff --git a/internal/genericosv/testdata/yaml/GHSA-28r2-q6m8-9hpx.yaml b/internal/genericosv/testdata/yaml/GHSA-28r2-q6m8-9hpx.yaml
index 595e938..ced34d5 100644
--- a/internal/genericosv/testdata/yaml/GHSA-28r2-q6m8-9hpx.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-28r2-q6m8-9hpx.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/hashicorp/go-getter
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml b/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml
index ca36393..237c791 100644
--- a/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-33m6-q9v5-62r7.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/apptainer/sif
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-3hwm-922r-47hw.yaml b/internal/genericosv/testdata/yaml/GHSA-3hwm-922r-47hw.yaml
index 46f05b1..b143380 100644
--- a/internal/genericosv/testdata/yaml/GHSA-3hwm-922r-47hw.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-3hwm-922r-47hw.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: atomys.codes/stud42
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-3wq5-3f56-v5xc.yaml b/internal/genericosv/testdata/yaml/GHSA-3wq5-3f56-v5xc.yaml
index 36769a1..a0a0100 100644
--- a/internal/genericosv/testdata/yaml/GHSA-3wq5-3f56-v5xc.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-3wq5-3f56-v5xc.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/mattermost/mattermost-server
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-54q4-74p3-mgcw.yaml b/internal/genericosv/testdata/yaml/GHSA-54q4-74p3-mgcw.yaml
index 1a82331..8a0333b 100644
--- a/internal/genericosv/testdata/yaml/GHSA-54q4-74p3-mgcw.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-54q4-74p3-mgcw.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/zhaojh329/rttys
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml b/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml
index ae29fee..826cec2 100644
--- a/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-5m6c-jp6f-2vcv.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/oauth2-proxy/oauth2-proxy
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml b/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml
index 6b9574f..c76a8e0 100644
--- a/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-627p-rr78-99rj.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/concourse/concourse
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml b/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml
index 21f8b1e..cf057a1 100644
--- a/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-66p8-j459-rq63.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/pterodactyl/wings
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml b/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml
index a057f18..2f3d1be 100644
--- a/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-69v6-xc2j-r2jf.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/ethereum/go-ethereum
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-6qfg-8799-r575.yaml b/internal/genericosv/testdata/yaml/GHSA-6qfg-8799-r575.yaml
index 2685a43..4426f33 100644
--- a/internal/genericosv/testdata/yaml/GHSA-6qfg-8799-r575.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-6qfg-8799-r575.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/kubernetes/kubernetes
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml b/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml
index 23ba044..af0e6c4 100644
--- a/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-6rg3-8h8x-5xfv.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/pterodactyl/wings
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml b/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml
index 5bc74d1..9e83b61 100644
--- a/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-7943-82jg-wmw5.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/argoproj/argo-cd
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-7fxj-fr3v-r9gj.yaml b/internal/genericosv/testdata/yaml/GHSA-7fxj-fr3v-r9gj.yaml
index 879ea72..8d191d1 100644
--- a/internal/genericosv/testdata/yaml/GHSA-7fxj-fr3v-r9gj.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-7fxj-fr3v-r9gj.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/pingcap/tidb
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-9689-rx4v-cqgc.yaml b/internal/genericosv/testdata/yaml/GHSA-9689-rx4v-cqgc.yaml
index 8c83046..cc17ac6 100644
--- a/internal/genericosv/testdata/yaml/GHSA-9689-rx4v-cqgc.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-9689-rx4v-cqgc.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/concourse/concourse
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml b/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml
index 05cfcf7..43c04e3 100644
--- a/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-cf7g-cm7q-rq7f.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/drakkan/sftpgo
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml b/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml
index 2f55b38..fa72bd8 100644
--- a/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-fv82-r8qv-ch4v.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/pomerium/pomerium
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml b/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml
index ee0d4f7..5316366 100644
--- a/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-g5gj-9ggf-9vmq.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/cloudflare/cfrpki
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml b/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml
index 38fc5eb..988a207 100644
--- a/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-g9wh-3vrx-r7hg.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/cloudflare/cfrpki
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-hjv9-hm2f-rpcj.yaml b/internal/genericosv/testdata/yaml/GHSA-hjv9-hm2f-rpcj.yaml
index b9b1a1a..377647e 100644
--- a/internal/genericosv/testdata/yaml/GHSA-hjv9-hm2f-rpcj.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-hjv9-hm2f-rpcj.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/grafana/grafana
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml b/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml
index 0afe597..4413651 100644
--- a/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-hmfx-3pcx-653p.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/containerd/containerd
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml b/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml
index 061b536..b0bc61d 100644
--- a/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-hv53-vf5m-8q94.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/personnummer/go
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-jh36-q97c-9928.yaml b/internal/genericosv/testdata/yaml/GHSA-jh36-q97c-9928.yaml
index 7f6e427..e929aa9 100644
--- a/internal/genericosv/testdata/yaml/GHSA-jh36-q97c-9928.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-jh36-q97c-9928.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: k8s.io/kubernetes
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml b/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml
index 2529536..ef47026 100644
--- a/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-jmp2-wc4p-wfh2.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/mutagen-io/mutagen
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml b/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml
index 7f2007e..c6430db 100644
--- a/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-pg5p-wwp8-97g8.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/cilium/cilium
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml b/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml
index 37e65ce..b884fd4 100644
--- a/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-pmfr-63c2-jr5c.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/sylabs/singularity
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml b/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml
index 82324e7..1b10c80 100644
--- a/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-vp35-85q5-9f25.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/moby/moby
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml b/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml
index ccb5ca5..6b3ec5e 100644
--- a/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-w4xh-w33p-4v29.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/git-lfs/git-lfs
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml b/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml
index efdfbed..f24a55e 100644
--- a/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-wx8q-rgfr-cf6v.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/google/exposure-notifications-verification-server
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml b/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml
index 9728fa8..8961798 100644
--- a/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-xmg8-99r8-jc2j.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/argoproj/argo-cd
       versions:
diff --git a/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml b/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml
index 16b70b3..a0ba03f 100644
--- a/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml
+++ b/internal/genericosv/testdata/yaml/GHSA-xx9w-464f-7h6f.yaml
@@ -1,4 +1,4 @@
-id: GO-TEST-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/goharbor/harbor
       versions:
diff --git a/internal/report/cve_test.go b/internal/report/cve_test.go
index 002f5f9..b1a269e 100644
--- a/internal/report/cve_test.go
+++ b/internal/report/cve_test.go
@@ -79,8 +79,6 @@
 	os.Exit(1)
 }
 
-const placeholderID = "PLACEHOLDER-ID"
-
 func TestCVEToReport(t *testing.T) {
 	pc, err := proxy.NewTestClient(t, *realProxy)
 	if err != nil {
@@ -91,7 +89,7 @@
 		return new(cveschema.CVE)
 	}
 	toReportV4 := func(cve cvelistrepo.CVE, modulePath string) *Report {
-		return New(ToCVE4(cve.(*cveschema.CVE)), placeholderID, modulePath, pc)
+		return New(ToCVE4(cve.(*cveschema.CVE)), pc, WithModulePath(modulePath))
 	}
 	if err := run(t, v4txtar, newV4, toReportV4); err != nil {
 		t.Fatal(err)
@@ -108,7 +106,8 @@
 		return new(cveschema5.CVERecord)
 	}
 	toReportV5 := func(cve cvelistrepo.CVE, modulePath string) *Report {
-		return New(ToCVE5(cve.(*cveschema5.CVERecord)), placeholderID, modulePath, pc)
+		return New(ToCVE5(cve.(*cveschema5.CVERecord)), pc,
+			WithModulePath(modulePath))
 	}
 	if err := run(t, v5txtar, newV5, toReportV5); err != nil {
 		t.Fatal(err)
diff --git a/internal/report/ghsa_test.go b/internal/report/ghsa_test.go
index 2138a60..82a023d 100644
--- a/internal/report/ghsa_test.go
+++ b/internal/report/ghsa_test.go
@@ -43,7 +43,7 @@
 			name:   "module provided",
 			module: "golang.org/x/tools",
 			want: &Report{
-				ID: placeholderID,
+				ID: pendingID,
 				Modules: []*Module{{
 					Module:       "golang.org/x/tools",
 					VulnerableAt: "0.8.0",
@@ -66,7 +66,7 @@
 			name:   "empty module attempts to find module from package",
 			module: "",
 			want: &Report{
-				ID: placeholderID,
+				ID: pendingID,
 				Modules: []*Module{{
 					Module: "golang.org/x/tools",
 					Versions: []VersionRange{
@@ -91,7 +91,7 @@
 	} {
 		test := test
 		t.Run(test.name, func(t *testing.T) {
-			got := New(ToLegacyGHSA(sa), placeholderID, test.module, pc)
+			got := New(ToLegacyGHSA(sa), pc, WithModulePath(test.module))
 			if diff := cmp.Diff(*got, *test.want); diff != "" {
 				t.Errorf("mismatch (-want, +got):\n%s", diff)
 			}
diff --git a/internal/report/new.go b/internal/report/new.go
index 0e94cb9..e878425 100644
--- a/internal/report/new.go
+++ b/internal/report/new.go
@@ -6,6 +6,7 @@
 
 import (
 	"context"
+	"time"
 
 	"golang.org/x/vulndb/internal/cveclient"
 	"golang.org/x/vulndb/internal/cveschema"
@@ -23,12 +24,19 @@
 	ToReport(modulePath string) *Report
 }
 
-func New(src Source, goID string, modulePath string, pc *proxy.Client) *Report {
-	r := src.ToReport(modulePath)
-	r.ID = goID
+func New(src Source, pc *proxy.Client, opts ...NewOption) *Report {
+	cfg := newCfg(opts)
+
+	r := src.ToReport(cfg.ModulePath)
+	r.ID = cfg.GoID
+	r.AddAliases(cfg.Aliases)
+
 	r.SourceMeta = &SourceMeta{
 		ID: src.SourceID(),
 	}
+	if !cfg.Created.IsZero() {
+		r.SourceMeta.Created = &cfg.Created
+	}
 
 	r.Fix(pc)
 	return r
@@ -38,6 +46,51 @@
 	Fetch(ctx context.Context, id string) (Source, error)
 }
 
+type NewOption func(*cfg)
+
+func WithModulePath(path string) NewOption {
+	return func(h *cfg) {
+		h.ModulePath = path
+	}
+}
+
+func WithAliases(aliases []string) NewOption {
+	return func(h *cfg) {
+		h.Aliases = aliases
+	}
+}
+
+func WithCreated(created time.Time) NewOption {
+	return func(h *cfg) {
+		h.Created = created
+	}
+}
+
+func WithGoID(id string) NewOption {
+	return func(h *cfg) {
+		h.GoID = id
+	}
+}
+
+type cfg struct {
+	ModulePath string
+	Aliases    []string
+	Created    time.Time
+	GoID       string
+}
+
+const pendingID = "GO-ID-PENDING"
+
+func newCfg(opts []NewOption) *cfg {
+	h := &cfg{
+		GoID: pendingID,
+	}
+	for _, opt := range opts {
+		opt(h)
+	}
+	return h
+}
+
 type cve5 struct {
 	*cveschema5.CVERecord
 }
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2020-9283.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2020-9283.txtar
index a830a6c..8fc9124 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2020-9283.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2020-9283.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2020-9283.
 
 -- CVE-2020-9283 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: golang.org/x/crypto
       vulnerable_at: 0.22.0
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-27919.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-27919.txtar
index 606ab29..a55976b 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-27919.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-27919.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2021-27919.
 
 -- CVE-2021-27919 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: std
       packages:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-3115.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-3115.txtar
index 85b0f83..6b3d11c 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-3115.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-3115.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2021-3115.
 
 -- CVE-2021-3115 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: cmd
       packages:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2022-39213.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2022-39213.txtar
index 4e065d0..031b68c 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2022-39213.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2022-39213.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2022-39213.
 
 -- CVE-2022-39213 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/pandatix/go-cvss
       versions:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-29407.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-29407.txtar
index ae6b582..57f9384 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-29407.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-29407.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2023-29407.
 
 -- CVE-2023-29407 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: golang.org/x/image
       versions:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-44378.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-44378.txtar
index 1200420..2899831 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-44378.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-44378.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2023-44378.
 
 -- CVE-2023-44378 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/consensys/gnark
       versions:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45141.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45141.txtar
index af3261d..e43e14b 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45141.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45141.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2023-45141.
 
 -- CVE-2023-45141 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/gofiber/fiber
       versions:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45283.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45283.txtar
index 1b3fa7a..206e5ba 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45283.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45283.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2023-45283.
 
 -- CVE-2023-45283 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: std
       versions:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45285.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45285.txtar
index de106a6..4d08a7e 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45285.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45285.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2023-45285.
 
 -- CVE-2023-45285 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: cmd
       versions:
diff --git a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45286.txtar b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45286.txtar
index f4e6c45..04e503c 100644
--- a/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45286.txtar
+++ b/internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45286.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVE5ToReport/CVE-2023-45286.
 
 -- CVE-2023-45286 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/go-resty/resty/v2
       unsupported_versions:
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2020-9283.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2020-9283.txtar
index 5bf0aac..0c1b5f8 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2020-9283.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2020-9283.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2020-9283.
 
 -- CVE-2020-9283 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: golang.org/x/crypto
       vulnerable_at: 0.22.0
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2021-27919.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2021-27919.txtar
index d44ad14..5509883 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2021-27919.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2021-27919.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2021-27919.
 
 -- CVE-2021-27919 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: std
       packages:
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2021-3115.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2021-3115.txtar
index 4d0a5c5..a8d928f 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2021-3115.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2021-3115.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2021-3115.
 
 -- CVE-2021-3115 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: std
       packages:
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2022-39213.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2022-39213.txtar
index ccda160..14bf6e4 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2022-39213.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2022-39213.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2022-39213.
 
 -- CVE-2022-39213 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/pandatix/go-cvss
       vulnerable_at: 0.6.2
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-29407.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-29407.txtar
index e69fbed..a8ed71a 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-29407.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-29407.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2023-29407.
 
 -- CVE-2023-29407 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: golang.org/x/image
       vulnerable_at: 0.15.0
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-44378.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-44378.txtar
index ddcf794..208b1b8 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-44378.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-44378.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2023-44378.
 
 -- CVE-2023-44378 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/Consensys/gnark
       vulnerable_at: 0.9.1
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45141.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45141.txtar
index 6824202..493bf9b 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45141.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45141.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2023-45141.
 
 -- CVE-2023-45141 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/gofiber/fiber
       vulnerable_at: 1.14.6
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45283.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45283.txtar
index 9c474c7..3f12e7e 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45283.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45283.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2023-45283.
 
 -- CVE-2023-45283 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: std
       packages:
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45285.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45285.txtar
index 10c3672..d073402 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45285.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45285.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2023-45285.
 
 -- CVE-2023-45285 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: std
       packages:
diff --git a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45286.txtar b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45286.txtar
index f1d1fb3..98428de 100644
--- a/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45286.txtar
+++ b/internal/report/testdata/cve/TestCVEToReport/CVE-2023-45286.txtar
@@ -5,7 +5,7 @@
 Expected output of TestCVEToReport/CVE-2023-45286.
 
 -- CVE-2023-45286 --
-id: PLACEHOLDER-ID
+id: GO-ID-PENDING
 modules:
     - module: github.com/go-resty/resty/v2
       vulnerable_at: 2.12.0
diff --git a/internal/worker/worker.go b/internal/worker/worker.go
index b950d7f..73ee464 100644
--- a/internal/worker/worker.go
+++ b/internal/worker/worker.go
@@ -256,8 +256,6 @@
 	return nil
 }
 
-const pendingID = "GO-ID-PENDING"
-
 func newCVEBody(sr storeRecord, rc *report.Client, pc *proxy.Client) (string, error) {
 	cr := sr.(*store.CVERecord)
 	var b strings.Builder
@@ -267,7 +265,7 @@
 	if cr.CVE.Metadata.ID == "" {
 		cr.CVE.Metadata.ID = cr.ID
 	}
-	r := report.New(report.ToCVE4(cr.CVE), pendingID, cr.Module, pc)
+	r := report.New(report.ToCVE4(cr.CVE), pc, report.WithModulePath(cr.Module))
 	r.Description = ""
 	out, err := r.ToString()
 	if err != nil {
@@ -367,7 +365,7 @@
 }
 
 func isDuplicate(sa *ghsa.SecurityAdvisory, pc *proxy.Client, rc *report.Client) bool {
-	r := report.New(report.ToLegacyGHSA(sa), pendingID, "", pc)
+	r := report.New(report.ToLegacyGHSA(sa), pc)
 	for _, aliases := range rc.XRef(r) {
 		if slices.Contains(aliases, sa.ID) {
 			return true
@@ -377,7 +375,7 @@
 }
 
 func CreateGHSABody(sa *ghsa.SecurityAdvisory, rc *report.Client, pc *proxy.Client) (body string, err error) {
-	r := report.New(report.ToLegacyGHSA(sa), pendingID, "", pc)
+	r := report.New(report.ToLegacyGHSA(sa), pc)
 	r.Description = ""
 	rs, err := r.ToString()
 	if err != nil {