diff --git a/cmd/api/src/services/upload/streamdecoder.go b/cmd/api/src/services/upload/streamdecoder.go index 113fb07c367f..b5b700e8a6de 100644 --- a/cmd/api/src/services/upload/streamdecoder.go +++ b/cmd/api/src/services/upload/streamdecoder.go @@ -295,13 +295,13 @@ func (s ValidationReport) BuildAPIError() []string { func (s ValidationReport) Error() string { var sb strings.Builder if len(s.CriticalErrors) > 0 { - sb.WriteString(fmt.Sprintf("(%d) critical error(s): [%s]", len(s.CriticalErrors), formatAggregateErrors(s.CriticalErrors))) + fmt.Fprintf(&sb, "(%d) critical error(s): [%s]", len(s.CriticalErrors), formatAggregateErrors(s.CriticalErrors)) if len(s.ValidationErrors) > 0 { sb.WriteString(", ") } } if len(s.ValidationErrors) > 0 { - sb.WriteString(fmt.Sprintf("(%d) validation error(s): [%s]", len(s.ValidationErrors), formatAggregateErrors(s.ValidationErrors))) + fmt.Fprintf(&sb, "(%d) validation error(s): [%s]", len(s.ValidationErrors), formatAggregateErrors(s.ValidationErrors)) } return sb.String() } @@ -310,7 +310,7 @@ func formatSchemaValidationError(arrayName string, index int, err error) string var sb strings.Builder if ve, ok := err.(*jsonschema.ValidationError); ok { numberOfViolations := len(ve.Causes) - sb.WriteString(fmt.Sprintf("%s[%d] schema validation failed with %d error(s): ", arrayName, index, numberOfViolations)) + fmt.Fprintf(&sb, "%s[%d] schema validation failed with %d error(s): ", arrayName, index, numberOfViolations) sb.WriteString("[") @@ -328,17 +328,13 @@ func formatSchemaValidationError(arrayName string, index int, err error) string switch { // Case: property value is an object (not allowed) case isPropertyError && isTypeError(cause, "object"): - sb.WriteString(fmt.Sprintf( - "Invalid property '%s': objects are not allowed in the property bag. Use only strings, numbers, booleans, nulls, or arrays of these types.", - propertyName, - )) + fmt.Fprintf(&sb, "Invalid property '%s': objects are not allowed in the property bag. Use only strings, numbers, booleans, nulls, or arrays of these types.", + propertyName) // Case: array contains a nested object (also not allowed) case isPropertyError && isNotError(cause): - sb.WriteString(fmt.Sprintf( - "Invalid property '%s': array contains an object. Arrays must contain only primitive values (string, number, boolean, or null).", - propertyName, - )) + fmt.Fprintf(&sb, "Invalid property '%s': array contains an object. Arrays must contain only primitive values (string, number, boolean, or null).", + propertyName) default: sb.WriteString(cause.Error()) diff --git a/packages/go/analysis/ad/adcs.go b/packages/go/analysis/ad/adcs.go index f41fa269c8c7..cdc82e852659 100644 --- a/packages/go/analysis/ad/adcs.go +++ b/packages/go/analysis/ad/adcs.go @@ -61,6 +61,15 @@ func PostADCS(ctx context.Context, db graph.Database, localGroupData *LocalGroup } else if step2Stats, err := postADCSPreProcessStep2(ctx, db, cache); err != nil { return &post.AtomicPostProcessingStats{}, cache, fmt.Errorf("failed adcs pre-processing step 2: %w", err) } else { + defer measure.ContextMeasure( + ctx, + slog.LevelInfo, + "ADCS ESC Processing", + attr.Namespace("analysis"), + attr.Function("PostADCS"), + attr.Scope("routine"), + )() + operation := post.NewPostRelationshipOperation(ctx, db, "ADCS Post Processing") operation.Stats.Merge(step1Stats) @@ -85,6 +94,15 @@ func PostADCS(ctx context.Context, db graph.Database, localGroupData *LocalGroup // postADCSPreProcessStep1 processes the edges that are not dependent on any other post-processed edges func postADCSPreProcessStep1(ctx context.Context, db graph.Database, enterpriseCertAuthorities, rootCertAuthorities, aiaCertAuthorities, certTemplates []*graph.Node) (*post.AtomicPostProcessingStats, error) { + defer measure.ContextMeasure( + ctx, + slog.LevelInfo, + "ADCS Post-processing Step 1", + attr.Namespace("analysis"), + attr.Function("postADCSPreProcessStep1"), + attr.Scope("routine"), + )() + operation := post.NewPostRelationshipOperation(ctx, db, "ADCS Post Processing Step 1") // TODO clean up the operation.Done() calls below @@ -107,6 +125,15 @@ func postADCSPreProcessStep1(ctx context.Context, db graph.Database, enterpriseC // postADCSPreProcessStep2 Processes the edges that are dependent on those processed in postADCSPreProcessStep1 func postADCSPreProcessStep2(ctx context.Context, db graph.Database, cache ADCSCache) (*post.AtomicPostProcessingStats, error) { + defer measure.ContextMeasure( + ctx, + slog.LevelInfo, + "ADCS Post-processing Step 2", + attr.Namespace("analysis"), + attr.Function("postADCSPreProcessStep2"), + attr.Scope("routine"), + )() + operation := post.NewPostRelationshipOperation(ctx, db, "ADCS Post Processing Step 2") if err := PostEnrollOnBehalfOf(cache, operation); err != nil { @@ -119,6 +146,16 @@ func postADCSPreProcessStep2(ctx context.Context, db graph.Database, cache ADCSC func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, targetDomains *graph.NodeSet, localGroupData *LocalGroupData, cache ADCSCache, operation post.StatTrackedOperation[post.EnsureRelationshipJob]) { operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing GoldenCert", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostGoldenCert(ctx, tx, outC, enterpriseCA, targetDomains); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -136,6 +173,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC1", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC1(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -153,6 +200,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC3", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC3(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -170,6 +227,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC4", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC4(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -187,6 +254,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC6a", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC6a(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -204,6 +281,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC6b", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC6b(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -221,6 +308,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC9a", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC9a(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -238,6 +335,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC9b", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC9b(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -255,6 +362,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC10a", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC10a(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -272,6 +389,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC10b", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC10b(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, @@ -289,6 +416,16 @@ func processEnterpriseCAWithValidCertChainToDomain(enterpriseCA *graph.Node, tar }) operation.Operation.SubmitReader(func(ctx context.Context, tx graph.Transaction, outC chan<- post.EnsureRelationshipJob) error { + defer measure.ContextMeasureWithThreshold( + ctx, + slog.LevelInfo, + "Post-processing ADCSESC13", + attr.Namespace("analysis"), + attr.Function("processEnterpriseCAWithValidCertChainToDomain"), + attr.Scope("routine"), + slog.Uint64("enterprise_ca_id", uint64(enterpriseCA.ID)), + )() + if err := PostADCSESC13(ctx, tx, outC, localGroupData, enterpriseCA, targetDomains, cache); errors.Is(err, graph.ErrPropertyNotFound) { slog.WarnContext( ctx, diff --git a/packages/go/analysis/ad/adcscache.go b/packages/go/analysis/ad/adcscache.go index ff93374d5c65..b7b91b51746d 100644 --- a/packages/go/analysis/ad/adcscache.go +++ b/packages/go/analysis/ad/adcscache.go @@ -94,6 +94,15 @@ func (s *ADCSCache) BuildCache(ctx context.Context, db graph.Database, enterpris s.enterpriseCertAuthorities = enterpriseCertAuthorities s.domains = domains } + certTemplateMeasure := measure.ContextMeasure( + ctx, + slog.LevelInfo, + "BuildCache cert template loop", + attr.Namespace("analysis"), + attr.Function("BuildCache.CertTemplates"), + attr.Scope("routine"), + ) + for _, ct := range s.certTemplates { // cert template enrollers if firstDegreePrincipals, err := fetchFirstDegreeNodes(tx, ct, ad.Enroll, ad.GenericAll, ad.AllExtendedRights); err != nil { @@ -132,6 +141,17 @@ func (s *ADCSCache) BuildCache(ctx context.Context, db graph.Database, enterpris } } + certTemplateMeasure() + + ecaMeasure := measure.ContextMeasure( + ctx, + slog.LevelInfo, + "BuildCache enterprise CA loop", + attr.Namespace("analysis"), + attr.Function("BuildCache.EnterpriseCAs"), + attr.Scope("routine"), + ) + for _, eca := range s.enterpriseCertAuthorities { if firstDegreeEnrollers, err := fetchFirstDegreeNodes(tx, eca, ad.Enroll); err != nil { slog.ErrorContext( @@ -187,6 +207,17 @@ func (s *ADCSCache) BuildCache(ctx context.Context, db graph.Database, enterpris } } + ecaMeasure() + + domainMeasure := measure.ContextMeasure( + ctx, + slog.LevelInfo, + "BuildCache domain loop", + attr.Namespace("analysis"), + attr.Function("BuildCache.Domains"), + attr.Scope("routine"), + ) + for _, domain := range s.domains { //TODO: This code is necessary for ADCS composition during post, but we have scrapped that as part of this initiative. Leaving this code for later use //if rootCaPaths, err := FetchEnterpriseCAsRootCAForPathToDomainFull(tx, domain); err != nil { @@ -249,6 +280,8 @@ func (s *ADCSCache) BuildCache(ctx context.Context, db graph.Database, enterpris } } + domainMeasure() + return nil }) if err != nil { diff --git a/packages/go/schemagen/generator/sql.go b/packages/go/schemagen/generator/sql.go index a2e944e408fc..c225ad47bb20 100644 --- a/packages/go/schemagen/generator/sql.go +++ b/packages/go/schemagen/generator/sql.go @@ -178,7 +178,7 @@ func GenerateExtensionSQLAzure(dir string, azSchema model.Azure) error { func GenerateExtensionSQL(name string, displayName string, version string, namespace, dir string, fileName string, nodeKinds []model.StringEnum, relationshipKinds []model.StringEnum, pathfindingRelationshipKinds []model.StringEnum) error { var sb strings.Builder - sb.WriteString(fmt.Sprintf("-- Code generated by Cuelang code gen. DO NOT EDIT!\n-- Cuelang source: %s/", SchemaSourceName)) + fmt.Fprintf(&sb, "-- Code generated by Cuelang code gen. DO NOT EDIT!\n-- Cuelang source: %s/", SchemaSourceName) sb.WriteString(` CREATE OR REPLACE FUNCTION genscript_upsert_kind(node_kind_name TEXT) RETURNS SMALLINT AS $$ @@ -300,20 +300,20 @@ $$ LANGUAGE plpgsql; sb.WriteString("\nDO $$\nDECLARE\n\textension_id INT;\n\tenvironment_id INT;\nBEGIN\n\tLOCK schema_extensions, schema_node_kinds, schema_relationship_kinds, kind;\n\n") - sb.WriteString(fmt.Sprintf("\tIF NOT EXISTS (SELECT id FROM schema_extensions WHERE name = '%s') THEN\n", name)) - sb.WriteString(fmt.Sprintf("\t\tINSERT INTO schema_extensions (name, display_name, version, is_builtin, namespace, created_at, updated_at) VALUES ('%s', '%s', '%s', true, '%s', NOW(), NOW()) RETURNING id INTO extension_id;\n", name, displayName, version, namespace)) + fmt.Fprintf(&sb, "\tIF NOT EXISTS (SELECT id FROM schema_extensions WHERE name = '%s') THEN\n", name) + fmt.Fprintf(&sb, "\t\tINSERT INTO schema_extensions (name, display_name, version, is_builtin, namespace, created_at, updated_at) VALUES ('%s', '%s', '%s', true, '%s', NOW(), NOW()) RETURNING id INTO extension_id;\n", name, displayName, version, namespace) sb.WriteString("\tELSE\n") - sb.WriteString(fmt.Sprintf("\t\tUPDATE schema_extensions SET display_name = '%s', version = '%s', namespace = '%s', updated_at = NOW() WHERE name = '%s' RETURNING id INTO extension_id;\n", displayName, version, namespace, name)) + fmt.Fprintf(&sb, "\t\tUPDATE schema_extensions SET display_name = '%s', version = '%s', namespace = '%s', updated_at = NOW() WHERE name = '%s' RETURNING id INTO extension_id;\n", displayName, version, namespace, name) sb.WriteString("\tEND IF;\n\n") sb.WriteString("\t-- Insert Node Kinds\n") for _, kind := range nodeKinds { - sb.WriteString(fmt.Sprintf("\tPERFORM genscript_upsert_kind('%s');\n", kind.GetRepresentation())) + fmt.Fprintf(&sb, "\tPERFORM genscript_upsert_kind('%s');\n", kind.GetRepresentation()) } sb.WriteString("\n\t-- Insert Relationship Kinds\n") for _, kind := range relationshipKinds { - sb.WriteString(fmt.Sprintf("\tPERFORM genscript_upsert_kind('%s');\n", kind.GetRepresentation())) + fmt.Fprintf(&sb, "\tPERFORM genscript_upsert_kind('%s');\n", kind.GetRepresentation()) } sb.WriteString("\n") @@ -321,7 +321,7 @@ $$ LANGUAGE plpgsql; for _, kind := range nodeKinds { iconInfo, found := nodeIcons[kind.GetRepresentation()] - sb.WriteString(fmt.Sprintf("\tPERFORM genscript_upsert_schema_node_kind(extension_id, '%s', '%s', '', %t, '%s', '%s');\n", kind.GetRepresentation(), kind.GetRepresentation(), found, iconInfo.Icon, iconInfo.Color)) + fmt.Fprintf(&sb, "\tPERFORM genscript_upsert_schema_node_kind(extension_id, '%s', '%s', '', %t, '%s', '%s');\n", kind.GetRepresentation(), kind.GetRepresentation(), found, iconInfo.Icon, iconInfo.Color) } traversableMap := make(map[string]struct{}) @@ -335,7 +335,7 @@ $$ LANGUAGE plpgsql; for _, kind := range relationshipKinds { _, traversable := traversableMap[kind.GetRepresentation()] - sb.WriteString(fmt.Sprintf("\tPERFORM genscript_upsert_schema_relationship_kind(extension_id, '%s', '', %t);\n", kind.GetRepresentation(), traversable)) + fmt.Fprintf(&sb, "\tPERFORM genscript_upsert_schema_relationship_kind(extension_id, '%s', '', %t);\n", kind.GetRepresentation(), traversable) } sb.WriteString("\n")