Merge "Update generateSPDXNamespace to generate a unique spdx doc namespace" am: fad3925959
am: db5ae5b97a
am: 8b4d141c5a
am: 9461d52447
Original change: https://android-review.googlesource.com/c/platform/build/+/2540830 Change-Id: Ib46dc116a5b3c31abf6ed39932c7ae2198b2e2b1 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
06736f5ffd
2 changed files with 132 additions and 33 deletions
|
@ -55,6 +55,7 @@ type context struct {
|
|||
product string
|
||||
stripPrefix []string
|
||||
creationTime creationTimeGetter
|
||||
buildid string
|
||||
}
|
||||
|
||||
func (ctx context) strip(installPath string) string {
|
||||
|
@ -124,6 +125,7 @@ Options:
|
|||
depsFile := flags.String("d", "", "Where to write the deps file")
|
||||
product := flags.String("product", "", "The name of the product for which the notice is generated.")
|
||||
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
|
||||
buildid := flags.String("build_id", "", "Uniquely identifies the build. (default timestamp)")
|
||||
|
||||
flags.Parse(expandedArgs)
|
||||
|
||||
|
@ -162,7 +164,7 @@ Options:
|
|||
ofile = obuf
|
||||
}
|
||||
|
||||
ctx := &context{ofile, os.Stderr, compliance.FS, *product, *stripPrefix, actualTime}
|
||||
ctx := &context{ofile, os.Stderr, compliance.FS, *product, *stripPrefix, actualTime, *buildid}
|
||||
|
||||
spdxDoc, deps, err := sbomGenerator(ctx, flags.Args()...)
|
||||
|
||||
|
@ -317,14 +319,21 @@ func inputFiles(lg *compliance.LicenseGraph, pmix *projectmetadata.Index, licens
|
|||
}
|
||||
|
||||
// generateSPDXNamespace generates a unique SPDX Document Namespace using a SHA1 checksum
|
||||
// and the CreationInfo.Created field as the date.
|
||||
func generateSPDXNamespace(created string) string {
|
||||
// Compute a SHA1 checksum of the CreationInfo.Created field.
|
||||
hash := sha1.Sum([]byte(created))
|
||||
checksum := hex.EncodeToString(hash[:])
|
||||
func generateSPDXNamespace(buildid string, created string, files ...string) string {
|
||||
|
||||
// Combine the checksum and timestamp to generate the SPDX Namespace.
|
||||
namespace := fmt.Sprintf("SPDXRef-DOCUMENT-%s-%s", created, checksum)
|
||||
seed := strings.Join(files, "")
|
||||
|
||||
if buildid == "" {
|
||||
seed += created
|
||||
} else {
|
||||
seed += buildid
|
||||
}
|
||||
|
||||
// Compute a SHA1 checksum of the seed.
|
||||
hash := sha1.Sum([]byte(seed))
|
||||
uuid := hex.EncodeToString(hash[:])
|
||||
|
||||
namespace := fmt.Sprintf("SPDXRef-DOCUMENT-%s", uuid)
|
||||
|
||||
return namespace
|
||||
}
|
||||
|
@ -523,7 +532,7 @@ func sbomGenerator(ctx *context, files ...string) (*spdx.Document, []string, err
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: docName,
|
||||
DocumentNamespace: generateSPDXNamespace(ci.Created),
|
||||
DocumentNamespace: generateSPDXNamespace(ctx.buildid, ci.Created, files...),
|
||||
CreationInfo: ci,
|
||||
Packages: pkgs,
|
||||
Relationships: relationships,
|
||||
|
|
|
@ -59,7 +59,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-firstparty-highest.apex",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/firstparty/highest.apex.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -187,7 +187,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-firstparty-application",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/firstparty/application.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -266,7 +266,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-firstparty-container.zip",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/firstparty/container.zip.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -394,7 +394,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-firstparty-bin-bin1",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/firstparty/bin/bin1.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -460,7 +460,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-firstparty-lib-libd.so",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/firstparty/lib/libd.so.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -500,7 +500,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-notice-highest.apex",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/notice/highest.apex.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -634,7 +634,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-notice-container.zip",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/notice/container.zip.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -768,7 +768,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-notice-application",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/notice/application.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -853,7 +853,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-notice-bin-bin1",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/notice/bin/bin1.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -925,7 +925,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-notice-lib-libd.so",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/notice/lib/libd.so.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -965,7 +965,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-reciprocal-highest.apex",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/reciprocal/highest.apex.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1105,7 +1105,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-reciprocal-application",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/reciprocal/application.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1196,7 +1196,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-reciprocal-bin-bin1",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/reciprocal/bin/bin1.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1268,7 +1268,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-reciprocal-lib-libd.so",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/reciprocal/lib/libd.so.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1308,7 +1308,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-restricted-highest.apex",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/restricted/highest.apex.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1454,7 +1454,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-restricted-container.zip",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/restricted/container.zip.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1600,7 +1600,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-restricted-bin-bin1",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/restricted/bin/bin1.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1678,7 +1678,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-restricted-lib-libd.so",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/restricted/lib/libd.so.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1718,7 +1718,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-proprietary-highest.apex",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/proprietary/highest.apex.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -1864,7 +1864,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-proprietary-container.zip",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/proprietary/container.zip.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -2010,7 +2010,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-proprietary-application",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/proprietary/application.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -2101,7 +2101,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-proprietary-bin-bin1",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/proprietary/bin/bin1.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -2173,7 +2173,7 @@ func Test(t *testing.T) {
|
|||
DataLicense: "CC0-1.0",
|
||||
SPDXIdentifier: "DOCUMENT",
|
||||
DocumentName: "testdata-proprietary-lib-libd.so",
|
||||
DocumentNamespace: generateSPDXNamespace("1970-01-01T00:00:00Z"),
|
||||
DocumentNamespace: generateSPDXNamespace("", "1970-01-01T00:00:00Z", "testdata/proprietary/lib/libd.so.meta_lic"),
|
||||
CreationInfo: getCreationInfo(t),
|
||||
Packages: []*spdx.Package{
|
||||
{
|
||||
|
@ -2215,7 +2215,7 @@ func Test(t *testing.T) {
|
|||
rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
|
||||
}
|
||||
|
||||
ctx := context{stdout, stderr, compliance.GetFS(tt.outDir), "", []string{tt.stripPrefix}, fakeTime}
|
||||
ctx := context{stdout, stderr, compliance.GetFS(tt.outDir), "", []string{tt.stripPrefix}, fakeTime, ""}
|
||||
|
||||
spdxDoc, deps, err := sbomGenerator(&ctx, rootFiles...)
|
||||
if err != nil {
|
||||
|
@ -2262,6 +2262,96 @@ func Test(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGenerateSPDXNamespace(t *testing.T) {
|
||||
|
||||
buildID1 := "example-1"
|
||||
buildID2 := "example-2"
|
||||
files1 := "file1"
|
||||
timestamp1 := "2022-05-01"
|
||||
timestamp2 := "2022-05-02"
|
||||
files2 := "file2"
|
||||
|
||||
// Test case 1: different timestamps, same files
|
||||
nsh1 := generateSPDXNamespace("", timestamp1, files1)
|
||||
nsh2 := generateSPDXNamespace("", timestamp2, files1)
|
||||
|
||||
if nsh1 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", "", timestamp1, files1)
|
||||
}
|
||||
|
||||
if nsh2 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", "", timestamp2, files1)
|
||||
}
|
||||
|
||||
if nsh1 == nsh2 {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s) and generateSPDXNamespace(%s, %s, %s): expected different namespace hashes, but got the same", "", timestamp1, files1, "", timestamp2, files1)
|
||||
}
|
||||
|
||||
// Test case 2: different build ids, same timestamps and files
|
||||
nsh1 = generateSPDXNamespace(buildID1, timestamp1, files1)
|
||||
nsh2 = generateSPDXNamespace(buildID2, timestamp1, files1)
|
||||
|
||||
if nsh1 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", buildID1, timestamp1, files1)
|
||||
}
|
||||
|
||||
if nsh2 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", buildID2, timestamp1, files1)
|
||||
}
|
||||
|
||||
if nsh1 == nsh2 {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s) and generateSPDXNamespace(%s, %s, %s): expected different namespace hashes, but got the same", buildID1, timestamp1, files1, buildID2, timestamp1, files1)
|
||||
}
|
||||
|
||||
// Test case 3: same build ids and files, different timestamps
|
||||
nsh1 = generateSPDXNamespace(buildID1, timestamp1, files1)
|
||||
nsh2 = generateSPDXNamespace(buildID1, timestamp2, files1)
|
||||
|
||||
if nsh1 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", buildID1, timestamp1, files1)
|
||||
}
|
||||
|
||||
if nsh2 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", buildID1, timestamp2, files1)
|
||||
}
|
||||
|
||||
if nsh1 != nsh2 {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s) and generateSPDXNamespace(%s, %s, %s): expected same namespace hashes, but got different: %s and %s", buildID1, timestamp1, files1, buildID2, timestamp1, files1, nsh1, nsh2)
|
||||
}
|
||||
|
||||
// Test case 4: same build ids and timestamps, different files
|
||||
nsh1 = generateSPDXNamespace(buildID1, timestamp1, files1)
|
||||
nsh2 = generateSPDXNamespace(buildID1, timestamp1, files2)
|
||||
|
||||
if nsh1 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", buildID1, timestamp1, files1)
|
||||
}
|
||||
|
||||
if nsh2 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", buildID1, timestamp1, files2)
|
||||
}
|
||||
|
||||
if nsh1 == nsh2 {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s) and generateSPDXNamespace(%s, %s, %s): expected different namespace hashes, but got the same", buildID1, timestamp1, files1, buildID1, timestamp1, files2)
|
||||
}
|
||||
|
||||
// Test case 5: empty build ids, same timestamps and different files
|
||||
nsh1 = generateSPDXNamespace("", timestamp1, files1)
|
||||
nsh2 = generateSPDXNamespace("", timestamp1, files2)
|
||||
|
||||
if nsh1 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", "", timestamp1, files1)
|
||||
}
|
||||
|
||||
if nsh2 == "" {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s): expected non-empty string, but got empty string", "", timestamp1, files2)
|
||||
}
|
||||
|
||||
if nsh1 == nsh2 {
|
||||
t.Errorf("generateSPDXNamespace(%s, %s, %s) and generateSPDXNamespace(%s, %s, %s): expected different namespace hashes, but got the same", "", timestamp1, files1, "", timestamp1, files2)
|
||||
}
|
||||
}
|
||||
|
||||
func getCreationInfo(t *testing.T) *spdx.CreationInfo {
|
||||
ci, err := builder2v2.BuildCreationInfoSection2_2("Organization", "Google LLC", nil)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue