1package daemon23import (4 "context"5 "errors"6 "fmt"78 "github.com/FelineStateMachine/tinyrelay/internal/event"9 "github.com/FelineStateMachine/tinyrelay/internal/policy"10 "github.com/FelineStateMachine/tinyrelay/internal/storage"11)1213// validatePrivateRepositoryPlacement prevents a private GRASP repository from14// being admitted to an open tenant. State events inherit the marker from their15// stored announcement, including when the announcement predates this guard.16func (t *Tenant) validatePrivateRepositoryPlacement(ctx context.Context, e event.Event) error {17 if e.Kind != event.KIND_REPO && e.Kind != event.KIND_REPO_STATE {18 return nil19 }20 private, err := privateRepositoryStored(ctx, t.store, e)21 if err != nil {22 return fmt.Errorf("check private repository placement: %w", err)23 }24 if !private {25 return nil26 }27 p := t.Policy()28 if !p.Features.Grasp08 || p.Reads != "members" {29 return errors.New("blocked: private repositories require a GRASP-08 private tenant")30 }31 return nil32}3334func hasLegacyPrivateRepository(ctx context.Context, store *storage.Store) (bool, error) {35 if store == nil {36 return false, errors.New("private repository scan: missing store")37 }38 return store.HasPrivateRepositories(ctx)39}4041func privateRepositoryStored(ctx context.Context, store *storage.Store, e event.Event) (bool, error) {42 return policy.PrivateRepository(ctx, store, e)43}