mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
Hanzo CI/CD / test (linux-amd64) (push) Skipped
Hanzo CI/CD / test (linux-arm64) (push) Skipped
Hanzo CI/CD / test-advisory (push) Failing after 5m15s
Hanzo CI/CD / test-amd64 (push) Failing after 17m40s
Hanzo CI/CD / cicd (push) Skipped
CI/CD / cicd (push) Failing after 17m53s
The event plane folded every occurrence into event.fact, and the Sentry module still read and wrote event.error. Its reads now select the error signal of event.fact, mapping issue, env, origin and the severity band. Errors enter through /v1/event only. The Sentry envelope and store routes, DSN keys and their rotation leave the module; the consumer of event.error files each fact through Ingest(org, product), which keeps the issue lifecycle and returns the issues a batch created.
81 lines
2.6 KiB
Go
81 lines
2.6 KiB
Go
package implsentry
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/hanzoai/o11y/pkg/errors"
|
|
"github.com/hanzoai/o11y/pkg/sqlstore"
|
|
"github.com/hanzoai/o11y/pkg/types/sentrytypes"
|
|
"github.com/hanzoai/o11y/pkg/valuer"
|
|
)
|
|
|
|
// projectStore backs o11y_sentry_projects. Every method is org-scoped except Resolve
|
|
// (the DSN-authenticated ingest lookup, keyed by the unguessable project id).
|
|
type projectStore struct {
|
|
sqlstore sqlstore.SQLStore
|
|
}
|
|
|
|
// NewProjectStore wires the relational projects store.
|
|
func NewProjectStore(sqlstore sqlstore.SQLStore) sentrytypes.ProjectStore {
|
|
return &projectStore{sqlstore: sqlstore}
|
|
}
|
|
|
|
func (s *projectStore) Create(ctx context.Context, p *sentrytypes.Project) error {
|
|
_, err := s.sqlstore.BunDBCtx(ctx).NewInsert().Model(p).Exec(ctx)
|
|
if err != nil {
|
|
return s.sqlstore.WrapAlreadyExistsErrf(err, sentrytypes.ErrCodeSentryConflict, "a project named %q already exists in the org", p.Slug)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *projectStore) List(ctx context.Context, orgID valuer.UUID) ([]*sentrytypes.Project, error) {
|
|
projects := make([]*sentrytypes.Project, 0)
|
|
// MANDATORY tenant boundary, first predicate — there is no unscoped project list.
|
|
err := s.sqlstore.BunDBCtx(ctx).
|
|
NewSelect().
|
|
Model(&projects).
|
|
Where("org_id = ?", orgID).
|
|
OrderExpr("created_at DESC").
|
|
Scan(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return projects, nil
|
|
}
|
|
|
|
func (s *projectStore) Get(ctx context.Context, orgID, id valuer.UUID) (*sentrytypes.Project, error) {
|
|
p := new(sentrytypes.Project)
|
|
err := s.sqlstore.BunDBCtx(ctx).
|
|
NewSelect().
|
|
Model(p).
|
|
Where("org_id = ?", orgID).
|
|
Where("id = ?", id).
|
|
Scan(ctx)
|
|
if err != nil {
|
|
return nil, s.sqlstore.WrapNotFoundErrf(err, sentrytypes.ErrCodeSentryNotFound, "project %s not found in the org", id)
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// Delete removes the project, org-scoped. Zero rows affected means it does not
|
|
// belong to the caller's org (or never existed) — reported as not-found so a caller
|
|
// can never probe another tenant's ids by watching for a different error.
|
|
//
|
|
// Retained events are deliberately left alone: they live in the columnar plane keyed
|
|
// by (org, project), and a name/naming fix must not double as a history wipe.
|
|
func (s *projectStore) Delete(ctx context.Context, orgID, id valuer.UUID) error {
|
|
res, err := s.sqlstore.BunDBCtx(ctx).
|
|
NewDelete().
|
|
Model((*sentrytypes.Project)(nil)).
|
|
Where("org_id = ?", orgID).
|
|
Where("id = ?", id).
|
|
Exec(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n, _ := res.RowsAffected(); n == 0 {
|
|
return errors.Newf(errors.TypeNotFound, sentrytypes.ErrCodeSentryNotFound, "project %s not found in the org", id)
|
|
}
|
|
return nil
|
|
}
|