Skip to content

Conversation

@socialyadept
Copy link

@socialyadept socialyadept commented Feb 9, 2026

Introduces new constraint kind enum CONSTRAINT_KIND_ALLOWED_OPTIONS and allowed_option_values to the constraint message proto. This allows us to expand the capability of our constraints to be able to limit string field options to only to allowed values based on a dependent (secondary_field_names) field selection.

Summary by CodeRabbit

  • New Features
    • Added "Allowed Options" constraint: when related context fields are present, a primary field's value must be one of a configured set; invalid values produce descriptive errors listing the field, allowed values, and related context.
  • Tests
    • Added coverage for allowed-options across scenarios: secondary present/absent, primary present/absent, and multiple secondaries.

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Walkthrough

Added CONSTRAINT_KIND_ALLOWED_OPTIONS to the proto, passed the full args struct into constraint validation, and implemented allowed-option enforcement for primary fields when specified secondary fields are present; tests added to cover AllowedOptions scenarios. (47 words)

Changes

Cohort / File(s) Summary
Proto Configuration
proto/c1/config/v1/config.proto
Added CONSTRAINT_KIND_ALLOWED_OPTIONS = 5 to ConstraintKind and repeated string allowed_option_values = 7 to Constraint.
Constraint Validation Logic
pkg/actions/actions.go
Updated validateConstraint signature to accept args *structpb.Struct and implemented handling for CONSTRAINT_KIND_ALLOWED_OPTIONS: when any secondary field is present, ensure primary string field values (from args) are within allowed_option_values, returning descriptive errors on violations.
Tests
pkg/actions/actions_test.go
Added subtests covering AllowedOptions: allowed/disallowed primary values with secondary present, primary absent, secondary absent, and multiple-secondary-field cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop through proto fields with cheer,
Allowed options now appear,
I peek at args with careful eyes,
Nibble wrong values — out they fly! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately describes the main change: adding a new constraint type (CONSTRAINT_KIND_ALLOWED_OPTIONS) to the baton config schema, which is reflected in both the proto changes and implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kumail/action-schema-constraints

Comment @coderabbitai help to get the list of available commands and usage tips.

string name = 4; // optional
string help_text = 5; // optional
bool is_field_group = 6;
repeated string allowed_option_values = 7;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StringField already has a StringRules that lets you specify a whitelist of allowed values.

repeated string in = 10;
StringField also has a StringFieldOption that lets you specify options for a dropdown or select widget. StringSliceField has a similar RepeatedStringRules that lets you do the same thing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The StringRules.in field handles static validation... a fixed whitelist that applies unconditionally. Our case is different: we need conditional constraints where the allowed values for one field change based on the value of another field.

Concrete example from the GitHub connector: when creating a team, the privacy field normally allows secret or closed. But if the user sets parent (making it a child team), privacy must be restricted to only closed. This is a cross-field dependency that StringRules.in can't express.

More details and a video walkthrough: DIR-146

I implemented this with Constraint messages on the action schema:

Github PR with an example code is shared below:

Constraints: []*config.Constraint{
			{
				Kind:                config.ConstraintKind_CONSTRAINT_KIND_ALLOWED_OPTIONS,
				FieldNames:          []string{"privacy"},
				SecondaryFieldNames: []string{"parent"},
				AllowedOptionValues: []string{"closed"}, // options limited only when parent is set
				Name:                "Privacy must be closed if parent is set",
				HelpText:            "Privacy must be closed if parent is set",
			},
		},

https://github.com/ConductorOne/baton-github/blob/59d95fd29f928b7ce46a365e5501114ab85c176c/pkg/connector/team.go#L392

The alternative would be to add conditional logic directly to the rules, something like:

message StringRules {
  // ... existing fields

  // Conditionally override this rule when another field matches a value.
  ConditionWhen when = 28;
}

message ConditionWhen {
  // The field whose value triggers this condition.
  string field_name = 1;
  // The condition applies when the field matches any of these values.
  repeated string field_values = 2;
}

But that couples validation rules to cross-field awareness, which gets complex quickly (nested conditions, multiple dependencies, etc.).

What do you think?

@kans
Copy link
Contributor

kans commented Feb 11, 2026

Add some unit tests.

@socialyadept socialyadept force-pushed the kumail/action-schema-constraints branch from 7c35e9a to 63e3bd3 Compare February 11, 2026 20:06
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@pkg/actions/actions.go`:
- Around line 608-637: The AllowedOptions branch (case
ConstraintKind_CONSTRAINT_KIND_ALLOWED_OPTIONS) currently skips enforcement when
c.GetSecondaryFieldNames() is empty; modify the logic that computes
anySecondaryPresent (derived from uniqueSecondaryFieldNames :=
deduplicateStrings(c.GetSecondaryFieldNames())) so that an empty secondary list
is treated as "always applicable" (i.e., set anySecondaryPresent = true when
len(uniqueSecondaryFieldNames) == 0), then proceed with building allowedValues
and validating args/uniqueFieldNames as before; update the check that loops
present[name] to only run when there are secondary names, otherwise fallback to
the always-applicable path so unconditional AllowedOptions are enforced.
🧹 Nitpick comments (1)
pkg/actions/actions_test.go (1)

468-571: Add a test for “no secondary fields” enforcement.
These tests cover conditional enforcement, but there’s no case ensuring AllowedOptions applies when secondary_field_names is empty (unconditional mode). Adding one will guard the expected behavior.

➕ Suggested test
 t.Run("Primary field absent passes regardless - AllowedOptions", func(t *testing.T) {
@@
 	require.NoError(t, err)
 })
+
+t.Run("No secondary fields enforces allowed options - AllowedOptions", func(t *testing.T) {
+	constraints := []*config.Constraint{
+		config.Constraint_builder{
+			Kind:                config.ConstraintKind_CONSTRAINT_KIND_ALLOWED_OPTIONS,
+			FieldNames:          []string{"field_a"},
+			AllowedOptionValues: []string{"value_a", "value_b"},
+		}.Build(),
+	}
+	args := &structpb.Struct{
+		Fields: map[string]*structpb.Value{
+			"field_a": structpb.NewStringValue("value_c"),
+		},
+	}
+	err := validateActionConstraints(constraints, args)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "not allowed")
+})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants