diff --git a/internal/output/emitter.go b/internal/output/emitter.go index 477f883c2..fb0b04f79 100644 --- a/internal/output/emitter.go +++ b/internal/output/emitter.go @@ -12,10 +12,10 @@ import ( ) const ( - // Keep each pretty-output scan window comfortably below the content-safety - // scanner's per-string limit. The overlap covers rule matches that cross a - // window boundary without coupling this package to that private limit. - prettySafetyScanWindowBytes = 64 << 10 + // Match the native content-safety scanner's 128 KiB per-string capacity so + // rendered-output scanning does not impose a smaller regex match window. + // The overlap keeps realistic rule matches visible across window boundaries. + prettySafetyScanWindowBytes = 128 << 10 prettySafetyScanOverlapBytes = 4 << 10 ) diff --git a/internal/output/emitter_contract_test.go b/internal/output/emitter_contract_test.go index 402f369ac..844f72b86 100644 --- a/internal/output/emitter_contract_test.go +++ b/internal/output/emitter_contract_test.go @@ -45,9 +45,8 @@ func (p *truncatingContractSafetyProvider) Name() string { } func (p *truncatingContractSafetyProvider) Scan(_ context.Context, req extcs.ScanRequest) (*extcs.Alert, error) { - // This deliberately differs from the production scanner's private limit; it - // models any provider that bounds work independently for each string. - const perStringCap = 160 << 10 + // Model the production scanner's native per-string capacity. + const perStringCap = 128 << 10 var containsMatch func(any) bool containsMatch = func(data any) bool { switch value := data.(type) { @@ -231,13 +230,13 @@ func TestEmitterPrettyBlockScansRenderedTextBeforeWriting(t *testing.T) { } } -func TestEmitterPrettyBlockScansLargeRenderedTextPastPerStringCap(t *testing.T) { +func TestEmitterPrettyBlockDetectsLongMatchPastFirstScanWindow(t *testing.T) { t.Setenv("LARKSUITE_CLI_CONTENT_SAFETY_MODE", "block") - const match = "blocked phrase" - // Place the match beyond the scanner's per-string cap and across a scan - // window boundary. A single-string scan misses it; overlapping windows keep - // the complete match visible to the provider. - rendered := strings.Repeat("a", 188410) + match + "\n" + const nativePerStringCap = 128 << 10 + // The match starts after the first native-capacity window and is longer than + // the old 64 KiB window. A native-capacity later window must retain it whole. + match := strings.Repeat("blocked", 10<<10) + rendered := strings.Repeat("a", nativePerStringCap+1) + match + "\n" provider := &truncatingContractSafetyProvider{ alert: &extcs.Alert{ Provider: "truncating-emitter-contract", diff --git a/shortcuts/common/runner.go b/shortcuts/common/runner.go index 43ad29ea4..99e2b7861 100644 --- a/shortcuts/common/runner.go +++ b/shortcuts/common/runner.go @@ -944,9 +944,18 @@ func runShortcut(cmd *cobra.Command, f *cmdutil.Factory, s *Shortcut, botOnly bo // own format flag (e.g. base +record-list's markdown|json, mail +watch's // json|data) owns a different enum, already validated by validateEnumFlags. if !shortcutDeclaresFormatFlag(s) { - if _, err := output.ParseFormatStrict(rctx.Format); err != nil { + format, err := output.ParseFormatStrict(rctx.Format) + if err != nil { return err } + canonicalFormat := format.String() + if rctx.Str("format") != canonicalFormat { + if err := rctx.Cmd.Flags().Set("format", canonicalFormat); err != nil { + return errs.NewInternalError(errs.SubtypeUnknown, + "failed to canonicalize the framework --format value").WithCause(err) + } + } + rctx.Format = canonicalFormat } if s.Validate != nil { if err := s.Validate(rctx.ctx, rctx); err != nil { diff --git a/shortcuts/common/runner_jq_test.go b/shortcuts/common/runner_jq_test.go index c979034ba..fd33319b9 100644 --- a/shortcuts/common/runner_jq_test.go +++ b/shortcuts/common/runner_jq_test.go @@ -367,6 +367,40 @@ func TestRunShortcut_DryRunMixedCasePrettyUsesPlainTextPreview(t *testing.T) { } } +func TestRunShortcut_MixedCaseFrameworkFormatIsCanonicalized(t *testing.T) { + var runtimeFormat string + var flagFormat string + prettyBranchFired := false + s := &Shortcut{ + Service: "test", + Command: "test-shortcut", + AuthTypes: []string{"bot"}, + Execute: func(_ context.Context, rctx *RuntimeContext) error { + runtimeFormat = rctx.Format + flagFormat = rctx.Str("format") + prettyBranchFired = rctx.Format == "pretty" + return nil + }, + } + f := newTestFactory() + cmd := newTestShortcutCmd(s, f) + cmd.Flags().Set("format", "PRETTY") + cmd.Flags().Set("as", "bot") + + if err := runShortcut(cmd, f, s, false); err != nil { + t.Fatalf("runShortcut() error = %v", err) + } + if runtimeFormat != "pretty" { + t.Fatalf("RuntimeContext.Format = %q, want pretty", runtimeFormat) + } + if flagFormat != "pretty" { + t.Fatalf("RuntimeContext.Str(\"format\") = %q, want pretty", flagFormat) + } + if !prettyBranchFired { + t.Fatal("downstream RuntimeContext.Format == \"pretty\" branch did not fire") + } +} + func TestRunShortcut_UnknownFormatErrorIncludesPretty(t *testing.T) { s := &Shortcut{ Service: "test",