[engine] Disallow *args and **kwargs in check impls

I can't think of a good use case for allowing check functions to have
arbitrary **kwargs and especially *args, so disallow them for now,
especially since it's not clear how they should interact with the
`check.with_args()` function.

Change-Id: I2ee786e325ec72f4788ae687ab712431194c274d
Reviewed-on: https://fuchsia-review.googlesource.com/c/shac-project/shac/+/920972
Fuchsia-Auto-Submit: Oliver Newman <olivernewman@google.com>
Commit-Queue: Oliver Newman <olivernewman@google.com>
Reviewed-by: Anthony Fandrianto <atyfto@google.com>
Reviewed-by: Marc-Antoine Ruel <maruel@google.com>
diff --git a/internal/engine/run_test.go b/internal/engine/run_test.go
index 32b1ca1..5c09186 100644
--- a/internal/engine/run_test.go
+++ b/internal/engine/run_test.go
@@ -1549,6 +1549,16 @@
 			"  //load-recurse.star:15:1: in <toplevel>\n",
 		},
 		{
+			"shac-check-star_args.star",
+			"shac.check: \"impl\" must not accept *args",
+			"  //shac-check-star_args.star:18:31: in <toplevel>\n",
+		},
+		{
+			"shac-check-star_kwargs.star",
+			"shac.check: \"impl\" must not accept **kwargs",
+			"  //shac-check-star_kwargs.star:18:31: in <toplevel>\n",
+		},
+		{
 			"shac-check-with_args-ctx.star",
 			"with_args: \"ctx\" argument cannot be overridden",
 			"  //shac-check-with_args-ctx.star:18:45: in <toplevel>\n",
@@ -1605,7 +1615,7 @@
 		},
 		{
 			"shac-register_check-multiple_required_args.star",
-			"shac.register_check: \"impl\" can only have one required argument",
+			"shac.register_check: \"impl\" cannot have required arguments besides \"ctx\"",
 			"  //shac-register_check-multiple_required_args.star:18:20: in <toplevel>\n",
 		},
 		{
diff --git a/internal/engine/runtime_shac_check.go b/internal/engine/runtime_shac_check.go
index e6ec24f..cf2cb5c 100644
--- a/internal/engine/runtime_shac_check.go
+++ b/internal/engine/runtime_shac_check.go
@@ -55,11 +55,27 @@
 	if fun.ParamDefault(0) != nil {
 		return nil, errors.New("\"impl\" must not have a default value for the \"ctx\" parameter")
 	}
-	for i := 1; i < fun.NumParams(); i++ {
-		if fun.ParamDefault(i) == nil {
-			return nil, errors.New("\"impl\" can only have one required argument")
-		}
+
+	// Checks should not accept arbitrary positional or keyword arguments. This
+	// restriction can be reconsidered if there turns out to be a valid use
+	// case.
+	if fun.HasVarargs() {
+		return nil, errors.New("\"impl\" must not accept *args")
 	}
+	if fun.HasKwargs() {
+		return nil, errors.New("\"impl\" must not accept **kwargs")
+	}
+
+	// Check impl functions are called internally by shac without any arguments
+	// by default, so they will fail if they have any required arguments.
+	//
+	// It's only necessary to check the first parameter after "ctx" because it's
+	// illegal for any required parameters to come after optional ones, so if
+	// the first parameter is optional then the rest are as well.
+	if fun.NumParams() > 1 && fun.ParamDefault(1) == nil {
+		return nil, errors.New("\"impl\" cannot have required arguments besides \"ctx\"")
+	}
+
 	if name == "" {
 		if fun.Name() == "lambda" {
 			return nil, errors.New("\"name\" must be set when \"impl\" is a lambda")
diff --git a/internal/engine/testdata/fail_or_throw/shac-check-star_args.star b/internal/engine/testdata/fail_or_throw/shac-check-star_args.star
new file mode 100644
index 0000000..6d05756
--- /dev/null
+++ b/internal/engine/testdata/fail_or_throw/shac-check-star_args.star
@@ -0,0 +1,18 @@
+# Copyright 2023 The Shac Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+def cb(ctx, *args):
+    pass
+
+shac.register_check(shac.check(cb))
diff --git a/internal/engine/testdata/fail_or_throw/shac-check-star_kwargs.star b/internal/engine/testdata/fail_or_throw/shac-check-star_kwargs.star
new file mode 100644
index 0000000..855479e
--- /dev/null
+++ b/internal/engine/testdata/fail_or_throw/shac-check-star_kwargs.star
@@ -0,0 +1,18 @@
+# Copyright 2023 The Shac Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+def cb(ctx, **kwargs):
+    pass
+
+shac.register_check(shac.check(cb))
diff --git a/internal/engine/version.go b/internal/engine/version.go
index 24ed15a..9433863 100644
--- a/internal/engine/version.go
+++ b/internal/engine/version.go
@@ -18,5 +18,5 @@
 	// Version is the current tool version.
 	//
 	// TODO(maruel): Add proper version, preferably from git tag.
-	Version = [...]int{0, 1, 6}
+	Version = [...]int{0, 1, 7}
 )
diff --git a/shac.textproto b/shac.textproto
index bc4b74c..eec752b 100644
--- a/shac.textproto
+++ b/shac.textproto
@@ -15,7 +15,7 @@
 # TODO(olivernewman): Build github.com/protocolbuffers/txtpbfmt into shac and
 # enforce formatting of shac.textproto files in all repos that use shac.
 
-min_shac_version: "0.1.6"
+min_shac_version: "0.1.7"
 allow_network: False
 ignore: "/vendor/"
 # Vendored code for test data only.