Skip to content

Commit

Permalink
Merge pull request #10 from ossf/feat/v2
Browse files Browse the repository at this point in the history
feat: Added go package to support v2 ingestion
  • Loading branch information
eddie-knight authored Jan 1, 2025
2 parents a899029 + d60ed1a commit 5d48a32
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 0 deletions.
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/ossf/si-tooling

go 1.23

require gopkg.in/yaml.v3 v3.0.1
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file added v2/README.md
Empty file.
85 changes: 85 additions & 0 deletions v2/si/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package si

import (
"encoding/json"
"fmt"
"io"
"net/http"

"gopkg.in/yaml.v3"
)

type FileAPIResponse struct {
ByteContent []byte `json:"content"`
SHA string `json:"sha"`
}

type SIBuilder struct {
TargetSI SecurityInsights
ParentSI SecurityInsights
}

func makeApiCall(endpoint, token string) (bytes []byte, err error) {
request, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
return
}
if token != "" {
request.Header.Set("Authorization", "Bearer "+token)
}
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
err = fmt.Errorf("error making http call: %s", err.Error())
return
}
if response.StatusCode != 200 {
err = fmt.Errorf("unexpected response: %s", response.Status)
return
}
return io.ReadAll(response.Body)
}

func getGitHubSourceFile(endpoint string) (response FileAPIResponse, err error) {
responseData, err := makeApiCall("https://api.github.com/"+endpoint, "")
if err != nil {
return
}
err = json.Unmarshal(responseData, &response)
return
}

func Read(owner, repo, path string) (si SecurityInsights, err error) {
var builder SIBuilder
// Get Target SI
response, err := getGitHubSourceFile(fmt.Sprintf("repos/%s/%s/contents/%s", owner, repo, path))
if err != nil {
err = fmt.Errorf("error reading target SI: %s", err.Error())
return
}

err = yaml.Unmarshal(response.ByteContent, &builder.TargetSI)
if err != nil {
err = fmt.Errorf("error unmarshalling target SI: %s", err.Error())
return
}

// check for parent SI, read if exists
if builder.TargetSI.Header.ProjectSISource != "" {
response, err = getGitHubSourceFile(builder.TargetSI.Header.ProjectSISource)
if err != nil {
err = fmt.Errorf("error reading parent SI: %s", err.Error())
return
}
err = yaml.Unmarshal(response.ByteContent, &builder.ParentSI)
if err != nil {
err = fmt.Errorf("error unmarshalling parent SI: %s", err.Error())
return
}
}

// Override target SI project data with contents of parent SI project data
builder.TargetSI.Project = builder.ParentSI.Project

return builder.TargetSI, nil
}
28 changes: 28 additions & 0 deletions v2/si/import_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package si

import (
"fmt"
"testing"
)

func TestRead(t *testing.T) {
testData := []struct {
owner string
repo string
path string
}{
{"ossf", "security-insights-spec", ".github/security-insights.yml"},
}

for _, tt := range testData {
t.Run(fmt.Sprintf("Read(%s, %s, %s)", tt.owner, tt.repo, tt.path), func(t *testing.T) {
// TODO: Add real test cases
out, err := Read(tt.owner, tt.repo, tt.path)
if err != nil {
t.Errorf("Read() error = %v", err)
return
}
fmt.Print(out)
})
}
}
146 changes: 146 additions & 0 deletions v2/si/security-insights.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package si

type SecurityInsights struct {
Header Header `yaml:"header"`
Project Project `yaml:"project"`
Repository Repository `yaml:"repository"`
}

type Header struct {
LastReviewed string `yaml:"last-reviewed"`
LastUpdated string `yaml:"last-updated"`
SchemaVersion string `yaml:"schema-version"`
URL string `yaml:"url"`
Comment string `yaml:"comment"`
ProjectSISource string `yaml:"project-si-source"`
}

type Assessment struct {
Comment string `yaml:"comment"`
Name string `yaml:"name"`
Evidence string `yaml:"evidence"`
Date string `yaml:"date"`
}

type Attestation struct {
Name string `yaml:"name"`
Location string `yaml:"location"`
PredicateURI string `yaml:"predicate-uri"`
Comment string `yaml:"comment"`
}

type Contact struct {
Name string `yaml:"name"`
Primary bool `yaml:"primary"`
Affiliation string `yaml:"affiliation"`
Email string `yaml:"email"`
Social string `yaml:"social"`
}

type License struct {
URL string `yaml:"url"`
Expression string `yaml:"expression"`
}

type Link struct {
URI string `yaml:"uri"`
Comment string `yaml:"comment"`
}

type Project struct {
Name string `yaml:"name"`
Homepage string `yaml:"homepage"`
Roadmap string `yaml:"roadmap"`
Funding string `yaml:"funding"`
Administrators []Contact `yaml:"administrators"`
Repositories []Repo `yaml:"repositories"`
Vulnerability VulnReport `yaml:"vulnerability-reporting"`
Documentation Docs `yaml:"documentation"`
}

type Repo struct {
Name string `yaml:"name"`
Comment string `yaml:"comment"`
URL string `yaml:"url"`
}

type VulnReport struct {
ReportsAccepted bool `yaml:"reports-accepted"`
BugBountyAvailable bool `yaml:"bug-bounty-available"`
BugBountyProgram string `yaml:"bug-bounty-program"`
Contact Contact `yaml:"contact"`
Comment string `yaml:"comment"`
SecurityPolicy string `yaml:"security-policy"`
PGPKey string `yaml:"pgp-key"`
InScope []string `yaml:"in-scope"`
OutOfScope []string `yaml:"out-of-scope"`
}

type Docs struct {
DetailedGuide string `yaml:"detailed-guide"`
CodeOfConduct string `yaml:"code-of-conduct"`
QuickstartGuide string `yaml:"quickstart-guide"`
ReleaseProcess string `yaml:"release-process"`
SignatureVerification string `yaml:"signature-verification"`
}

type Repository struct {
Status string `yaml:"status"`
URL string `yaml:"url"`
AcceptsChangeRequest bool `yaml:"accepts-change-request"`
AcceptsAutomatedChangeRequest bool `yaml:"accepts-automated-change-request"`
BugFixesOnly bool `yaml:"bug-fixes-only"`
NoThirdPartyPackages bool `yaml:"no-third-party-packages"`
CoreTeam []Contact `yaml:"core-team"`
License License `yaml:"license"`
Security SecurityInfo `yaml:"security"`
Documentation Docs `yaml:"documentation"`
Release Release `yaml:"release"`
}

type SecurityInfo struct {
Assessments Assessments `yaml:"assessments"`
Champions []Contact `yaml:"champions"`
Tools []Tool `yaml:"tools"`
}

type Assessments struct {
Self Assessment `yaml:"self"`
ThirdParty []Assessment `yaml:"third-party"`
}

type Tool struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Version string `yaml:"version"`
Comment string `yaml:"comment"`
Rulesets []string `yaml:"rulesets"`
Integration Integration `yaml:"integration"`
Results Results `yaml:"results"`
}

type Integration struct {
Adhoc bool `yaml:"adhoc"`
CI bool `yaml:"ci"`
Release bool `yaml:"release"`
}

type Results struct {
Adhoc Attestation `yaml:"adhoc"`
CI Attestation `yaml:"ci"`
Release Attestation `yaml:"release"`
}

type Release struct {
AutomatedPipeline bool `yaml:"automated-pipeline"`
DistributionPoints []Link `yaml:"distribution-points"`
Changelog string `yaml:"changelog"`
License License `yaml:"license"`
Attestations []Attestation `yaml:"attestations"`
}

type SIHeader struct {
SchemaVersion string `yaml:"schema-version"`
ChangeLogURL string `yaml:"changelog"`
LicenseURL string `yaml:"license"`
}

0 comments on commit 5d48a32

Please sign in to comment.