mirror of
https://github.com/coder/coder.git
synced 2026-06-05 22:18:20 +00:00
chore!: remove JFrog integration (#17353)
- Removes displaying XRay scan results in the dashboard. I'm not sure anyone was even using this integration so it's just debt for us to maintain. We can open up a separate issue to get rid of the db tables once we know for sure that we haven't broken anyone.
This commit is contained in:
Generated
-103
@@ -1432,84 +1432,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/integrations/jfrog/xray-scan": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Enterprise"
|
||||
],
|
||||
"summary": "Get JFrog XRay scan by workspace agent ID.",
|
||||
"operationId": "get-jfrog-xray-scan-by-workspace-agent-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Workspace ID",
|
||||
"name": "workspace_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Agent ID",
|
||||
"name": "agent_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.JFrogXrayScan"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Enterprise"
|
||||
],
|
||||
"summary": "Post JFrog XRay scan by workspace agent ID.",
|
||||
"operationId": "post-jfrog-xray-scan-by-workspace-agent-id",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Post JFrog XRay scan request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.JFrogXrayScan"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/licenses": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -12579,31 +12501,6 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.JFrogXrayScan": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"critical": {
|
||||
"type": "integer"
|
||||
},
|
||||
"high": {
|
||||
"type": "integer"
|
||||
},
|
||||
"medium": {
|
||||
"type": "integer"
|
||||
},
|
||||
"results_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.JobErrorCode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
||||
Generated
-93
@@ -1249,74 +1249,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/integrations/jfrog/xray-scan": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Enterprise"],
|
||||
"summary": "Get JFrog XRay scan by workspace agent ID.",
|
||||
"operationId": "get-jfrog-xray-scan-by-workspace-agent-id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Workspace ID",
|
||||
"name": "workspace_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Agent ID",
|
||||
"name": "agent_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.JFrogXrayScan"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"tags": ["Enterprise"],
|
||||
"summary": "Post JFrog XRay scan by workspace agent ID.",
|
||||
"operationId": "post-jfrog-xray-scan-by-workspace-agent-id",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Post JFrog XRay scan request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.JFrogXrayScan"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/codersdk.Response"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/licenses": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -11311,31 +11243,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.JFrogXrayScan": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"critical": {
|
||||
"type": "integer"
|
||||
},
|
||||
"high": {
|
||||
"type": "integer"
|
||||
},
|
||||
"medium": {
|
||||
"type": "integer"
|
||||
},
|
||||
"results_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"workspace_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"codersdk.JobErrorCode": {
|
||||
"type": "string",
|
||||
"enum": ["REQUIRED_TEMPLATE_VARIABLES"],
|
||||
|
||||
@@ -1895,13 +1895,6 @@ func (q *querier) GetInboxNotificationsByUserID(ctx context.Context, userID data
|
||||
return fetchWithPostFilter(q.auth, policy.ActionRead, q.db.GetInboxNotificationsByUserID)(ctx, userID)
|
||||
}
|
||||
|
||||
func (q *querier) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg database.GetJFrogXrayScanByWorkspaceAndAgentIDParams) (database.JfrogXrayScan, error) {
|
||||
if _, err := fetch(q.log, q.auth, q.db.GetWorkspaceByID)(ctx, arg.WorkspaceID); err != nil {
|
||||
return database.JfrogXrayScan{}, err
|
||||
}
|
||||
return q.db.GetJFrogXrayScanByWorkspaceAndAgentID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) GetLastUpdateCheck(ctx context.Context) (string, error) {
|
||||
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
|
||||
return "", err
|
||||
@@ -4767,27 +4760,6 @@ func (q *querier) UpsertHealthSettings(ctx context.Context, value string) error
|
||||
return q.db.UpsertHealthSettings(ctx, value)
|
||||
}
|
||||
|
||||
func (q *querier) UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error {
|
||||
// TODO: Having to do all this extra querying makes me a sad panda.
|
||||
workspace, err := q.db.GetWorkspaceByID(ctx, arg.WorkspaceID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get workspace by id: %w", err)
|
||||
}
|
||||
|
||||
template, err := q.db.GetTemplateByID(ctx, workspace.TemplateID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get template by id: %w", err)
|
||||
}
|
||||
|
||||
// Only template admins should be able to write JFrog Xray scans to a workspace.
|
||||
// We don't want this to be a workspace-level permission because then users
|
||||
// could overwrite their own results.
|
||||
if err := q.authorizeContext(ctx, policy.ActionCreate, template); err != nil {
|
||||
return err
|
||||
}
|
||||
return q.db.UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) UpsertLastUpdateCheck(ctx context.Context, value string) error {
|
||||
if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceSystem); err != nil {
|
||||
return err
|
||||
|
||||
@@ -4293,74 +4293,6 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
s.Run("GetUserLinksByUserID", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args(uuid.New()).Asserts(rbac.ResourceSystem, policy.ActionRead)
|
||||
}))
|
||||
s.Run("GetJFrogXrayScanByWorkspaceAndAgentID", s.Subtest(func(db database.Store, check *expects) {
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
org := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
tpl := dbgen.Template(s.T(), db, database.Template{
|
||||
OrganizationID: org.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{
|
||||
OwnerID: u.ID,
|
||||
OrganizationID: org.ID,
|
||||
TemplateID: tpl.ID,
|
||||
})
|
||||
pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{})
|
||||
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{
|
||||
JobID: pj.ID,
|
||||
})
|
||||
agent := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{
|
||||
ResourceID: res.ID,
|
||||
})
|
||||
|
||||
err := db.UpsertJFrogXrayScanByWorkspaceAndAgentID(context.Background(), database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{
|
||||
AgentID: agent.ID,
|
||||
WorkspaceID: ws.ID,
|
||||
Critical: 1,
|
||||
High: 12,
|
||||
Medium: 14,
|
||||
ResultsUrl: "http://hello",
|
||||
})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
expect := database.JfrogXrayScan{
|
||||
WorkspaceID: ws.ID,
|
||||
AgentID: agent.ID,
|
||||
Critical: 1,
|
||||
High: 12,
|
||||
Medium: 14,
|
||||
ResultsUrl: "http://hello",
|
||||
}
|
||||
|
||||
check.Args(database.GetJFrogXrayScanByWorkspaceAndAgentIDParams{
|
||||
WorkspaceID: ws.ID,
|
||||
AgentID: agent.ID,
|
||||
}).Asserts(ws, policy.ActionRead).Returns(expect)
|
||||
}))
|
||||
s.Run("UpsertJFrogXrayScanByWorkspaceAndAgentID", s.Subtest(func(db database.Store, check *expects) {
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
org := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
tpl := dbgen.Template(s.T(), db, database.Template{
|
||||
OrganizationID: org.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{
|
||||
OwnerID: u.ID,
|
||||
OrganizationID: org.ID,
|
||||
TemplateID: tpl.ID,
|
||||
})
|
||||
pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{})
|
||||
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{
|
||||
JobID: pj.ID,
|
||||
})
|
||||
agent := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{
|
||||
ResourceID: res.ID,
|
||||
})
|
||||
check.Args(database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{
|
||||
WorkspaceID: ws.ID,
|
||||
AgentID: agent.ID,
|
||||
}).Asserts(tpl, policy.ActionCreate)
|
||||
}))
|
||||
s.Run("DeleteRuntimeConfig", s.Subtest(func(db database.Store, check *expects) {
|
||||
check.Args("test").Asserts(rbac.ResourceSystem, policy.ActionDelete)
|
||||
}))
|
||||
|
||||
@@ -222,7 +222,6 @@ type data struct {
|
||||
gitSSHKey []database.GitSSHKey
|
||||
groupMembers []database.GroupMemberTable
|
||||
groups []database.Group
|
||||
jfrogXRayScans []database.JfrogXrayScan
|
||||
licenses []database.License
|
||||
notificationMessages []database.NotificationMessage
|
||||
notificationPreferences []database.NotificationPreference
|
||||
@@ -3687,24 +3686,6 @@ func (q *FakeQuerier) GetInboxNotificationsByUserID(_ context.Context, params da
|
||||
return notifications, nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetJFrogXrayScanByWorkspaceAndAgentID(_ context.Context, arg database.GetJFrogXrayScanByWorkspaceAndAgentIDParams) (database.JfrogXrayScan, error) {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return database.JfrogXrayScan{}, err
|
||||
}
|
||||
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
for _, scan := range q.jfrogXRayScans {
|
||||
if scan.AgentID == arg.AgentID && scan.WorkspaceID == arg.WorkspaceID {
|
||||
return scan, nil
|
||||
}
|
||||
}
|
||||
|
||||
return database.JfrogXrayScan{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetLastUpdateCheck(_ context.Context) (string, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
@@ -4241,7 +4222,7 @@ func (q *FakeQuerier) GetPresetByID(ctx context.Context, presetID uuid.UUID) (da
|
||||
if preset.ID == presetID {
|
||||
tv, ok := versionMap[preset.TemplateVersionID]
|
||||
if !ok {
|
||||
return empty, fmt.Errorf("template version %v does not exist", preset.TemplateVersionID)
|
||||
return empty, xerrors.Errorf("template version %v does not exist", preset.TemplateVersionID)
|
||||
}
|
||||
return database.GetPresetByIDRow{
|
||||
ID: preset.ID,
|
||||
@@ -4256,7 +4237,7 @@ func (q *FakeQuerier) GetPresetByID(ctx context.Context, presetID uuid.UUID) (da
|
||||
}
|
||||
}
|
||||
|
||||
return empty, fmt.Errorf("preset %v does not exist", presetID)
|
||||
return empty, xerrors.Errorf("preset %v does not exist", presetID)
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetPresetByWorkspaceBuildID(_ context.Context, workspaceBuildID uuid.UUID) (database.TemplateVersionPreset, error) {
|
||||
@@ -11986,39 +11967,6 @@ func (q *FakeQuerier) UpsertHealthSettings(_ context.Context, data string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpsertJFrogXrayScanByWorkspaceAndAgentID(_ context.Context, arg database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error {
|
||||
err := validateDatabaseType(arg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
for i, scan := range q.jfrogXRayScans {
|
||||
if scan.AgentID == arg.AgentID && scan.WorkspaceID == arg.WorkspaceID {
|
||||
scan.Critical = arg.Critical
|
||||
scan.High = arg.High
|
||||
scan.Medium = arg.Medium
|
||||
scan.ResultsUrl = arg.ResultsUrl
|
||||
q.jfrogXRayScans[i] = scan
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gosimple
|
||||
q.jfrogXRayScans = append(q.jfrogXRayScans, database.JfrogXrayScan{
|
||||
WorkspaceID: arg.WorkspaceID,
|
||||
AgentID: arg.AgentID,
|
||||
Critical: arg.Critical,
|
||||
High: arg.High,
|
||||
Medium: arg.Medium,
|
||||
ResultsUrl: arg.ResultsUrl,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) UpsertLastUpdateCheck(_ context.Context, data string) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
@@ -858,13 +858,6 @@ func (m queryMetricsStore) GetInboxNotificationsByUserID(ctx context.Context, us
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg database.GetJFrogXrayScanByWorkspaceAndAgentIDParams) (database.JfrogXrayScan, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetJFrogXrayScanByWorkspaceAndAgentID(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("GetJFrogXrayScanByWorkspaceAndAgentID").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetLastUpdateCheck(ctx context.Context) (string, error) {
|
||||
start := time.Now()
|
||||
version, err := m.s.GetLastUpdateCheck(ctx)
|
||||
@@ -3042,13 +3035,6 @@ func (m queryMetricsStore) UpsertHealthSettings(ctx context.Context, value strin
|
||||
return r0
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error {
|
||||
start := time.Now()
|
||||
r0 := m.s.UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx, arg)
|
||||
m.queryLatencies.WithLabelValues("UpsertJFrogXrayScanByWorkspaceAndAgentID").Observe(time.Since(start).Seconds())
|
||||
return r0
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) UpsertLastUpdateCheck(ctx context.Context, value string) error {
|
||||
start := time.Now()
|
||||
r0 := m.s.UpsertLastUpdateCheck(ctx, value)
|
||||
|
||||
@@ -1729,21 +1729,6 @@ func (mr *MockStoreMockRecorder) GetInboxNotificationsByUserID(ctx, arg any) *go
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInboxNotificationsByUserID", reflect.TypeOf((*MockStore)(nil).GetInboxNotificationsByUserID), ctx, arg)
|
||||
}
|
||||
|
||||
// GetJFrogXrayScanByWorkspaceAndAgentID mocks base method.
|
||||
func (m *MockStore) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg database.GetJFrogXrayScanByWorkspaceAndAgentIDParams) (database.JfrogXrayScan, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetJFrogXrayScanByWorkspaceAndAgentID", ctx, arg)
|
||||
ret0, _ := ret[0].(database.JfrogXrayScan)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetJFrogXrayScanByWorkspaceAndAgentID indicates an expected call of GetJFrogXrayScanByWorkspaceAndAgentID.
|
||||
func (mr *MockStoreMockRecorder) GetJFrogXrayScanByWorkspaceAndAgentID(ctx, arg any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetJFrogXrayScanByWorkspaceAndAgentID", reflect.TypeOf((*MockStore)(nil).GetJFrogXrayScanByWorkspaceAndAgentID), ctx, arg)
|
||||
}
|
||||
|
||||
// GetLastUpdateCheck mocks base method.
|
||||
func (m *MockStore) GetLastUpdateCheck(ctx context.Context) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@@ -6415,20 +6400,6 @@ func (mr *MockStoreMockRecorder) UpsertHealthSettings(ctx, value any) *gomock.Ca
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertHealthSettings", reflect.TypeOf((*MockStore)(nil).UpsertHealthSettings), ctx, value)
|
||||
}
|
||||
|
||||
// UpsertJFrogXrayScanByWorkspaceAndAgentID mocks base method.
|
||||
func (m *MockStore) UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpsertJFrogXrayScanByWorkspaceAndAgentID", ctx, arg)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpsertJFrogXrayScanByWorkspaceAndAgentID indicates an expected call of UpsertJFrogXrayScanByWorkspaceAndAgentID.
|
||||
func (mr *MockStoreMockRecorder) UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx, arg any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertJFrogXrayScanByWorkspaceAndAgentID", reflect.TypeOf((*MockStore)(nil).UpsertJFrogXrayScanByWorkspaceAndAgentID), ctx, arg)
|
||||
}
|
||||
|
||||
// UpsertLastUpdateCheck mocks base method.
|
||||
func (m *MockStore) UpsertLastUpdateCheck(ctx context.Context, value string) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -200,7 +200,6 @@ type sqlcQuerier interface {
|
||||
// param created_at_opt: The created_at timestamp to filter by. This parameter is usd for pagination - it fetches notifications created before the specified timestamp if it is not the zero value
|
||||
// param limit_opt: The limit of notifications to fetch. If the limit is not specified, it defaults to 25
|
||||
GetInboxNotificationsByUserID(ctx context.Context, arg GetInboxNotificationsByUserIDParams) ([]InboxNotification, error)
|
||||
GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg GetJFrogXrayScanByWorkspaceAndAgentIDParams) (JfrogXrayScan, error)
|
||||
GetLastUpdateCheck(ctx context.Context) (string, error)
|
||||
GetLatestCryptoKeyByFeature(ctx context.Context, feature CryptoKeyFeature) (CryptoKey, error)
|
||||
GetLatestWorkspaceAppStatusesByWorkspaceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAppStatus, error)
|
||||
@@ -619,7 +618,6 @@ type sqlcQuerier interface {
|
||||
// The functional values are immutable and controlled implicitly.
|
||||
UpsertDefaultProxy(ctx context.Context, arg UpsertDefaultProxyParams) error
|
||||
UpsertHealthSettings(ctx context.Context, value string) error
|
||||
UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error
|
||||
UpsertLastUpdateCheck(ctx context.Context, value string) error
|
||||
UpsertLogoURL(ctx context.Context, value string) error
|
||||
// Insert or update notification report generator logs with recent activity.
|
||||
|
||||
@@ -3570,75 +3570,6 @@ func (q *sqlQuerier) UpsertTemplateUsageStats(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const getJFrogXrayScanByWorkspaceAndAgentID = `-- name: GetJFrogXrayScanByWorkspaceAndAgentID :one
|
||||
SELECT
|
||||
agent_id, workspace_id, critical, high, medium, results_url
|
||||
FROM
|
||||
jfrog_xray_scans
|
||||
WHERE
|
||||
agent_id = $1
|
||||
AND
|
||||
workspace_id = $2
|
||||
LIMIT
|
||||
1
|
||||
`
|
||||
|
||||
type GetJFrogXrayScanByWorkspaceAndAgentIDParams struct {
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg GetJFrogXrayScanByWorkspaceAndAgentIDParams) (JfrogXrayScan, error) {
|
||||
row := q.db.QueryRowContext(ctx, getJFrogXrayScanByWorkspaceAndAgentID, arg.AgentID, arg.WorkspaceID)
|
||||
var i JfrogXrayScan
|
||||
err := row.Scan(
|
||||
&i.AgentID,
|
||||
&i.WorkspaceID,
|
||||
&i.Critical,
|
||||
&i.High,
|
||||
&i.Medium,
|
||||
&i.ResultsUrl,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const upsertJFrogXrayScanByWorkspaceAndAgentID = `-- name: UpsertJFrogXrayScanByWorkspaceAndAgentID :exec
|
||||
INSERT INTO
|
||||
jfrog_xray_scans (
|
||||
agent_id,
|
||||
workspace_id,
|
||||
critical,
|
||||
high,
|
||||
medium,
|
||||
results_url
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (agent_id, workspace_id)
|
||||
DO UPDATE SET critical = $3, high = $4, medium = $5, results_url = $6
|
||||
`
|
||||
|
||||
type UpsertJFrogXrayScanByWorkspaceAndAgentIDParams struct {
|
||||
AgentID uuid.UUID `db:"agent_id" json:"agent_id"`
|
||||
WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"`
|
||||
Critical int32 `db:"critical" json:"critical"`
|
||||
High int32 `db:"high" json:"high"`
|
||||
Medium int32 `db:"medium" json:"medium"`
|
||||
ResultsUrl string `db:"results_url" json:"results_url"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg UpsertJFrogXrayScanByWorkspaceAndAgentIDParams) error {
|
||||
_, err := q.db.ExecContext(ctx, upsertJFrogXrayScanByWorkspaceAndAgentID,
|
||||
arg.AgentID,
|
||||
arg.WorkspaceID,
|
||||
arg.Critical,
|
||||
arg.High,
|
||||
arg.Medium,
|
||||
arg.ResultsUrl,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteLicense = `-- name: DeleteLicense :one
|
||||
DELETE
|
||||
FROM licenses
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
-- name: GetJFrogXrayScanByWorkspaceAndAgentID :one
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
jfrog_xray_scans
|
||||
WHERE
|
||||
agent_id = $1
|
||||
AND
|
||||
workspace_id = $2
|
||||
LIMIT
|
||||
1;
|
||||
|
||||
-- name: UpsertJFrogXrayScanByWorkspaceAndAgentID :exec
|
||||
INSERT INTO
|
||||
jfrog_xray_scans (
|
||||
agent_id,
|
||||
workspace_id,
|
||||
critical,
|
||||
high,
|
||||
medium,
|
||||
results_url
|
||||
)
|
||||
VALUES
|
||||
($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (agent_id, workspace_id)
|
||||
DO UPDATE SET critical = $3, high = $4, medium = $5, results_url = $6;
|
||||
@@ -1,50 +0,0 @@
|
||||
package codersdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type JFrogXrayScan struct {
|
||||
WorkspaceID uuid.UUID `json:"workspace_id" format:"uuid"`
|
||||
AgentID uuid.UUID `json:"agent_id" format:"uuid"`
|
||||
Critical int `json:"critical"`
|
||||
High int `json:"high"`
|
||||
Medium int `json:"medium"`
|
||||
ResultsURL string `json:"results_url"`
|
||||
}
|
||||
|
||||
func (c *Client) PostJFrogXrayScan(ctx context.Context, req JFrogXrayScan) error {
|
||||
res, err := c.Request(ctx, http.MethodPost, "/api/v2/integrations/jfrog/xray-scan", req)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("make request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusCreated {
|
||||
return ReadBodyAsError(res)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) JFrogXRayScan(ctx context.Context, workspaceID, agentID uuid.UUID) (JFrogXrayScan, error) {
|
||||
res, err := c.Request(ctx, http.MethodGet, "/api/v2/integrations/jfrog/xray-scan", nil,
|
||||
WithQueryParam("workspace_id", workspaceID.String()),
|
||||
WithQueryParam("agent_id", agentID.String()),
|
||||
)
|
||||
if err != nil {
|
||||
return JFrogXrayScan{}, xerrors.Errorf("make request: %w", err)
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return JFrogXrayScan{}, ReadBodyAsError(res)
|
||||
}
|
||||
|
||||
var resp JFrogXrayScan
|
||||
return resp, json.NewDecoder(res.Body).Decode(&resp)
|
||||
}
|
||||
Generated
-101
@@ -490,107 +490,6 @@ curl -X PATCH http://coder-server:8080/api/v2/groups/{group} \
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get JFrog XRay scan by workspace agent ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X GET http://coder-server:8080/api/v2/integrations/jfrog/xray-scan?workspace_id=string&agent_id=string \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`GET /integrations/jfrog/xray-scan`
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
|----------------|-------|--------|----------|--------------|
|
||||
| `workspace_id` | query | string | true | Workspace ID |
|
||||
| `agent_id` | query | string | true | Agent ID |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "2b1e3b65-2c04-4fa2-a2d7-467901e98978",
|
||||
"critical": 0,
|
||||
"high": 0,
|
||||
"medium": 0,
|
||||
"results_url": "string",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9"
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
|--------|---------------------------------------------------------|-------------|------------------------------------------------------------|
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.JFrogXrayScan](schemas.md#codersdkjfrogxrayscan) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Post JFrog XRay scan by workspace agent ID
|
||||
|
||||
### Code samples
|
||||
|
||||
```shell
|
||||
# Example request using curl
|
||||
curl -X POST http://coder-server:8080/api/v2/integrations/jfrog/xray-scan \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Accept: application/json' \
|
||||
-H 'Coder-Session-Token: API_KEY'
|
||||
```
|
||||
|
||||
`POST /integrations/jfrog/xray-scan`
|
||||
|
||||
> Body parameter
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "2b1e3b65-2c04-4fa2-a2d7-467901e98978",
|
||||
"critical": 0,
|
||||
"high": 0,
|
||||
"medium": 0,
|
||||
"results_url": "string",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9"
|
||||
}
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
| Name | In | Type | Required | Description |
|
||||
|--------|------|------------------------------------------------------------|----------|------------------------------|
|
||||
| `body` | body | [codersdk.JFrogXrayScan](schemas.md#codersdkjfrogxrayscan) | true | Post JFrog XRay scan request |
|
||||
|
||||
### Example responses
|
||||
|
||||
> 200 Response
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "string",
|
||||
"message": "string",
|
||||
"validations": [
|
||||
{
|
||||
"detail": "string",
|
||||
"field": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Responses
|
||||
|
||||
| Status | Meaning | Description | Schema |
|
||||
|--------|---------------------------------------------------------|-------------|--------------------------------------------------|
|
||||
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | [codersdk.Response](schemas.md#codersdkresponse) |
|
||||
|
||||
To perform this operation, you must be authenticated. [Learn more](authentication.md).
|
||||
|
||||
## Get licenses
|
||||
|
||||
### Code samples
|
||||
|
||||
Generated
-24
@@ -3414,30 +3414,6 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
|----------------|--------|----------|--------------|-------------|
|
||||
| `signed_token` | string | false | | |
|
||||
|
||||
## codersdk.JFrogXrayScan
|
||||
|
||||
```json
|
||||
{
|
||||
"agent_id": "2b1e3b65-2c04-4fa2-a2d7-467901e98978",
|
||||
"critical": 0,
|
||||
"high": 0,
|
||||
"medium": 0,
|
||||
"results_url": "string",
|
||||
"workspace_id": "0967198e-ec7b-4c6b-b4d3-f71244cadbe9"
|
||||
}
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
| Name | Type | Required | Restrictions | Description |
|
||||
|----------------|---------|----------|--------------|-------------|
|
||||
| `agent_id` | string | false | | |
|
||||
| `critical` | integer | false | | |
|
||||
| `high` | integer | false | | |
|
||||
| `medium` | integer | false | | |
|
||||
| `results_url` | string | false | | |
|
||||
| `workspace_id` | string | false | | |
|
||||
|
||||
## codersdk.JobErrorCode
|
||||
|
||||
```json
|
||||
|
||||
@@ -470,16 +470,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
|
||||
r.Get("/", api.userQuietHoursSchedule)
|
||||
r.Put("/", api.putUserQuietHoursSchedule)
|
||||
})
|
||||
r.Route("/integrations", func(r chi.Router) {
|
||||
r.Use(
|
||||
apiKeyMiddleware,
|
||||
api.jfrogEnabledMW,
|
||||
)
|
||||
|
||||
r.Post("/jfrog/xray-scan", api.postJFrogXrayScan)
|
||||
r.Get("/jfrog/xray-scan", api.jFrogXrayScan)
|
||||
})
|
||||
|
||||
// The /notifications base route is mounted by the AGPL router, so we can't group it here.
|
||||
// Additionally, because we have a static route for /notifications/templates/system which conflicts
|
||||
// with the below route, we need to register this route without any mounts or groups to make both work.
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
package coderd
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/httpapi"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
// Post workspace agent results for a JFrog XRay scan.
|
||||
//
|
||||
// @Summary Post JFrog XRay scan by workspace agent ID.
|
||||
// @ID post-jfrog-xray-scan-by-workspace-agent-id
|
||||
// @Security CoderSessionToken
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param request body codersdk.JFrogXrayScan true "Post JFrog XRay scan request"
|
||||
// @Success 200 {object} codersdk.Response
|
||||
// @Router /integrations/jfrog/xray-scan [post]
|
||||
func (api *API) postJFrogXrayScan(rw http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var req codersdk.JFrogXrayScan
|
||||
if !httpapi.Read(ctx, rw, r, &req) {
|
||||
return
|
||||
}
|
||||
|
||||
err := api.Database.UpsertJFrogXrayScanByWorkspaceAndAgentID(ctx, database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{
|
||||
WorkspaceID: req.WorkspaceID,
|
||||
AgentID: req.AgentID,
|
||||
// #nosec G115 - Vulnerability counts are small and fit in int32
|
||||
Critical: int32(req.Critical),
|
||||
// #nosec G115 - Vulnerability counts are small and fit in int32
|
||||
High: int32(req.High),
|
||||
// #nosec G115 - Vulnerability counts are small and fit in int32
|
||||
Medium: int32(req.Medium),
|
||||
ResultsUrl: req.ResultsURL,
|
||||
})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusCreated, codersdk.Response{
|
||||
Message: "Successfully inserted JFrog XRay scan!",
|
||||
})
|
||||
}
|
||||
|
||||
// Get workspace agent results for a JFrog XRay scan.
|
||||
//
|
||||
// @Summary Get JFrog XRay scan by workspace agent ID.
|
||||
// @ID get-jfrog-xray-scan-by-workspace-agent-id
|
||||
// @Security CoderSessionToken
|
||||
// @Produce json
|
||||
// @Tags Enterprise
|
||||
// @Param workspace_id query string true "Workspace ID"
|
||||
// @Param agent_id query string true "Agent ID"
|
||||
// @Success 200 {object} codersdk.JFrogXrayScan
|
||||
// @Router /integrations/jfrog/xray-scan [get]
|
||||
func (api *API) jFrogXrayScan(rw http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
ctx = r.Context()
|
||||
vals = r.URL.Query()
|
||||
p = httpapi.NewQueryParamParser()
|
||||
wsID = p.RequiredNotEmpty("workspace_id").UUID(vals, uuid.UUID{}, "workspace_id")
|
||||
agentID = p.RequiredNotEmpty("agent_id").UUID(vals, uuid.UUID{}, "agent_id")
|
||||
)
|
||||
|
||||
if len(p.Errors) > 0 {
|
||||
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Invalid query params.",
|
||||
Validations: p.Errors,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
scan, err := api.Database.GetJFrogXrayScanByWorkspaceAndAgentID(ctx, database.GetJFrogXrayScanByWorkspaceAndAgentIDParams{
|
||||
WorkspaceID: wsID,
|
||||
AgentID: agentID,
|
||||
})
|
||||
if httpapi.Is404Error(err) {
|
||||
httpapi.ResourceNotFound(rw)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpapi.InternalServerError(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
httpapi.Write(ctx, rw, http.StatusOK, codersdk.JFrogXrayScan{
|
||||
WorkspaceID: scan.WorkspaceID,
|
||||
AgentID: scan.AgentID,
|
||||
Critical: int(scan.Critical),
|
||||
High: int(scan.High),
|
||||
Medium: int(scan.Medium),
|
||||
ResultsURL: scan.ResultsUrl,
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API) jfrogEnabledMW(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
// This doesn't actually use the external auth feature but we want
|
||||
// to lock this behind an enterprise license and it's somewhat
|
||||
// related to external auth (in that it is JFrog integration).
|
||||
if !api.Entitlements.Enabled(codersdk.FeatureMultipleExternalAuth) {
|
||||
httpapi.RouteNotFound(rw)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package coderd_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/coderdtest"
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbfake"
|
||||
"github.com/coder/coder/v2/coderd/rbac"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/enterprise/coderd/coderdenttest"
|
||||
"github.com/coder/coder/v2/enterprise/coderd/license"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
)
|
||||
|
||||
func TestJFrogXrayScan(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Post/Get", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ownerClient, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{codersdk.FeatureMultipleExternalAuth: 1},
|
||||
},
|
||||
})
|
||||
|
||||
tac, ta := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID, rbac.RoleTemplateAdmin())
|
||||
|
||||
wsResp := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OrganizationID: owner.OrganizationID,
|
||||
OwnerID: ta.ID,
|
||||
}).WithAgent().Do()
|
||||
|
||||
ws := coderdtest.MustWorkspace(t, tac, wsResp.Workspace.ID)
|
||||
require.Len(t, ws.LatestBuild.Resources, 1)
|
||||
require.Len(t, ws.LatestBuild.Resources[0].Agents, 1)
|
||||
|
||||
agentID := ws.LatestBuild.Resources[0].Agents[0].ID
|
||||
expectedPayload := codersdk.JFrogXrayScan{
|
||||
WorkspaceID: ws.ID,
|
||||
AgentID: agentID,
|
||||
Critical: 19,
|
||||
High: 5,
|
||||
Medium: 3,
|
||||
ResultsURL: "https://hello-world",
|
||||
}
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
err := tac.PostJFrogXrayScan(ctx, expectedPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp1, err := tac.JFrogXRayScan(ctx, ws.ID, agentID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedPayload, resp1)
|
||||
|
||||
// Can update again without error.
|
||||
expectedPayload = codersdk.JFrogXrayScan{
|
||||
WorkspaceID: ws.ID,
|
||||
AgentID: agentID,
|
||||
Critical: 20,
|
||||
High: 22,
|
||||
Medium: 8,
|
||||
ResultsURL: "https://goodbye-world",
|
||||
}
|
||||
err = tac.PostJFrogXrayScan(ctx, expectedPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp2, err := tac.JFrogXRayScan(ctx, ws.ID, agentID)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, expectedPayload, resp1)
|
||||
require.Equal(t, expectedPayload, resp2)
|
||||
})
|
||||
|
||||
t.Run("MemberPostUnauthorized", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ownerClient, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
|
||||
LicenseOptions: &coderdenttest.LicenseOptions{
|
||||
Features: license.Features{codersdk.FeatureMultipleExternalAuth: 1},
|
||||
},
|
||||
})
|
||||
|
||||
memberClient, member := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
|
||||
|
||||
wsResp := dbfake.WorkspaceBuild(t, db, database.WorkspaceTable{
|
||||
OrganizationID: owner.OrganizationID,
|
||||
OwnerID: member.ID,
|
||||
}).WithAgent().Do()
|
||||
|
||||
ws := coderdtest.MustWorkspace(t, memberClient, wsResp.Workspace.ID)
|
||||
require.Len(t, ws.LatestBuild.Resources, 1)
|
||||
require.Len(t, ws.LatestBuild.Resources[0].Agents, 1)
|
||||
|
||||
agentID := ws.LatestBuild.Resources[0].Agents[0].ID
|
||||
expectedPayload := codersdk.JFrogXrayScan{
|
||||
WorkspaceID: ws.ID,
|
||||
AgentID: agentID,
|
||||
Critical: 19,
|
||||
High: 5,
|
||||
Medium: 3,
|
||||
ResultsURL: "https://hello-world",
|
||||
}
|
||||
|
||||
ctx := testutil.Context(t, testutil.WaitMedium)
|
||||
err := memberClient.PostJFrogXrayScan(ctx, expectedPayload)
|
||||
require.Error(t, err)
|
||||
cerr, ok := codersdk.AsError(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, http.StatusNotFound, cerr.StatusCode())
|
||||
|
||||
err = ownerClient.PostJFrogXrayScan(ctx, expectedPayload)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We should still be able to fetch.
|
||||
resp1, err := memberClient.JFrogXRayScan(ctx, ws.ID, agentID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expectedPayload, resp1)
|
||||
})
|
||||
}
|
||||
@@ -381,11 +381,6 @@ export type InsightsTemplateParams = InsightsParams & {
|
||||
interval: "day" | "week";
|
||||
};
|
||||
|
||||
export type GetJFrogXRayScanParams = {
|
||||
workspaceId: string;
|
||||
agentId: string;
|
||||
};
|
||||
|
||||
export class MissingBuildParameters extends Error {
|
||||
parameters: TypesGen.TemplateVersionParameter[] = [];
|
||||
versionId: string;
|
||||
@@ -2277,29 +2272,6 @@ class ApiMethods {
|
||||
await this.axios.delete(`/api/v2/workspaces/${workspaceID}/favorite`);
|
||||
};
|
||||
|
||||
getJFrogXRayScan = async (options: GetJFrogXRayScanParams) => {
|
||||
const searchParams = new URLSearchParams({
|
||||
workspace_id: options.workspaceId,
|
||||
agent_id: options.agentId,
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await this.axios.get<TypesGen.JFrogXrayScan>(
|
||||
`/api/v2/integrations/jfrog/xray-scan?${searchParams}`,
|
||||
);
|
||||
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
if (isAxiosError(error) && error.response?.status === 404) {
|
||||
// react-query library does not allow undefined to be returned as a
|
||||
// query result
|
||||
return null;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
postWorkspaceUsage = async (
|
||||
workspaceID: string,
|
||||
options: PostWorkspaceUsageRequest,
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { GetJFrogXRayScanParams } from "api/api";
|
||||
import { API } from "api/api";
|
||||
|
||||
export const xrayScan = (params: GetJFrogXRayScanParams) => {
|
||||
return {
|
||||
queryKey: ["xray", params],
|
||||
queryFn: () => API.getJFrogXRayScan(params),
|
||||
};
|
||||
};
|
||||
Generated
-10
@@ -1171,16 +1171,6 @@ export interface IssueReconnectingPTYSignedTokenResponse {
|
||||
readonly signed_token: string;
|
||||
}
|
||||
|
||||
// From codersdk/jfrog.go
|
||||
export interface JFrogXrayScan {
|
||||
readonly workspace_id: string;
|
||||
readonly agent_id: string;
|
||||
readonly critical: number;
|
||||
readonly high: number;
|
||||
readonly medium: number;
|
||||
readonly results_url: string;
|
||||
}
|
||||
|
||||
// From codersdk/provisionerdaemons.go
|
||||
export type JobErrorCode = "REQUIRED_TEMPLATE_VARIABLES";
|
||||
|
||||
|
||||
@@ -299,27 +299,6 @@ export const Deprecated: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithXRayScan: Story = {
|
||||
parameters: {
|
||||
queries: [
|
||||
{
|
||||
key: [
|
||||
"xray",
|
||||
{ agentId: M.MockWorkspaceAgent.id, workspaceId: M.MockWorkspace.id },
|
||||
],
|
||||
data: {
|
||||
workspace_id: M.MockWorkspace.id,
|
||||
agent_id: M.MockWorkspaceAgent.id,
|
||||
critical: 10,
|
||||
high: 3,
|
||||
medium: 5,
|
||||
results_url: "http://localhost:8080",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const HideApp: Story = {
|
||||
args: {
|
||||
agent: {
|
||||
|
||||
@@ -4,7 +4,6 @@ import Collapse from "@mui/material/Collapse";
|
||||
import Divider from "@mui/material/Divider";
|
||||
import Skeleton from "@mui/material/Skeleton";
|
||||
import { API } from "api/api";
|
||||
import { xrayScan } from "api/queries/integrations";
|
||||
import type {
|
||||
Template,
|
||||
Workspace,
|
||||
@@ -41,7 +40,6 @@ import { PortForwardButton } from "./PortForwardButton";
|
||||
import { AgentSSHButton } from "./SSHButton/SSHButton";
|
||||
import { TerminalLink } from "./TerminalLink/TerminalLink";
|
||||
import { VSCodeDesktopButton } from "./VSCodeDesktopButton/VSCodeDesktopButton";
|
||||
import { XRayScanAlert } from "./XRayScanAlert";
|
||||
|
||||
export interface AgentRowProps {
|
||||
agent: WorkspaceAgent;
|
||||
@@ -72,11 +70,6 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
storybookAgentMetadata,
|
||||
sshPrefix,
|
||||
}) => {
|
||||
// XRay integration
|
||||
const xrayScanQuery = useQuery(
|
||||
xrayScan({ workspaceId: workspace.id, agentId: agent.id }),
|
||||
);
|
||||
|
||||
// Apps visibility
|
||||
const visibleApps = agent.apps.filter((app) => !app.hidden);
|
||||
const hasAppsToDisplay = !hideVSCodeDesktopButton || visibleApps.length > 0;
|
||||
@@ -227,8 +220,6 @@ export const AgentRow: FC<AgentRowProps> = ({
|
||||
)}
|
||||
</header>
|
||||
|
||||
{xrayScanQuery.data && <XRayScanAlert scan={xrayScanQuery.data} />}
|
||||
|
||||
<div css={styles.content}>
|
||||
{agent.status === "connected" && (
|
||||
<section css={styles.apps}>
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import type { Interpolation, Theme } from "@emotion/react";
|
||||
import type { JFrogXrayScan } from "api/typesGenerated";
|
||||
import { Button } from "components/Button/Button";
|
||||
import { ExternalImage } from "components/ExternalImage/ExternalImage";
|
||||
import type { FC } from "react";
|
||||
|
||||
interface XRayScanAlertProps {
|
||||
scan: JFrogXrayScan;
|
||||
}
|
||||
|
||||
export const XRayScanAlert: FC<XRayScanAlertProps> = ({ scan }) => {
|
||||
const display = scan.critical > 0 || scan.high > 0 || scan.medium > 0;
|
||||
return display ? (
|
||||
<div role="alert" css={styles.root}>
|
||||
<ExternalImage
|
||||
alt="JFrog logo"
|
||||
src="/icon/jfrog.svg"
|
||||
css={{ width: 40, height: 40 }}
|
||||
/>
|
||||
<div>
|
||||
<span css={styles.title}>
|
||||
JFrog Xray detected new vulnerabilities for this agent
|
||||
</span>
|
||||
|
||||
<ul css={styles.issues}>
|
||||
{scan.critical > 0 && (
|
||||
<li css={[styles.critical, styles.issueItem]}>
|
||||
{scan.critical} critical
|
||||
</li>
|
||||
)}
|
||||
{scan.high > 0 && (
|
||||
<li css={[styles.high, styles.issueItem]}>{scan.high} high</li>
|
||||
)}
|
||||
{scan.medium > 0 && (
|
||||
<li css={[styles.medium, styles.issueItem]}>
|
||||
{scan.medium} medium
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
<div css={styles.link}>
|
||||
<Button size="sm" variant="subtle" asChild>
|
||||
<a href={scan.results_url} target="_blank" rel="noreferrer">
|
||||
Review results
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = {
|
||||
root: (theme) => ({
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
borderLeft: 0,
|
||||
borderRight: 0,
|
||||
fontSize: 14,
|
||||
padding: "24px 16px 24px 32px",
|
||||
lineHeight: "1.5",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 24,
|
||||
}),
|
||||
title: {
|
||||
display: "block",
|
||||
fontWeight: 500,
|
||||
},
|
||||
issues: {
|
||||
listStyle: "none",
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: 13,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 16,
|
||||
marginTop: 4,
|
||||
},
|
||||
issueItem: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
|
||||
"&:before": {
|
||||
content: '""',
|
||||
display: "block",
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: "50%",
|
||||
backgroundColor: "currentColor",
|
||||
},
|
||||
},
|
||||
critical: (theme) => ({
|
||||
color: theme.roles.error.fill.solid,
|
||||
}),
|
||||
high: (theme) => ({
|
||||
color: theme.roles.warning.fill.solid,
|
||||
}),
|
||||
medium: (theme) => ({
|
||||
color: theme.roles.notice.fill.solid,
|
||||
}),
|
||||
link: {
|
||||
marginLeft: "auto",
|
||||
alignSelf: "flex-start",
|
||||
},
|
||||
} satisfies Record<string, Interpolation<Theme>>;
|
||||
@@ -374,8 +374,4 @@ export const handlers = [
|
||||
http.get("/api/v2/workspaceagents/:agent/listening-ports", () => {
|
||||
return HttpResponse.json(M.MockListeningPortsResponse);
|
||||
}),
|
||||
|
||||
http.get("/api/v2/integrations/jfrog/xray-scan", () => {
|
||||
return new HttpResponse(null, { status: 404 });
|
||||
}),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user