# Implement Your Checks

Shisho Cloud's native inspection capabilities cover a wide range of inspection items for many cloud services. However, you may want to implement inspection items specific to your company. In such cases, you can extend the inspection capabilities provided by Shisho Cloud.

This tutorial explains how to extend the inspection capabilities provided by Shisho Cloud. Specifically, you will practice the following:

- Registering inspection specifications (**Specification**) with Shisho Cloud
- Writing and deploying Shisho Cloud policies

## Preparation

The steps differ depending on the language in which the policy is written.

<Tabs groupId="policy-lang" queryString>
  <TabItem value="rego" label="Rego" default>

After cloning the Shisho Cloud Rego SDK as follows, create a `your-policy` directory as a place to store the policy code you will create in this tutorial:

```bash
git clone https://github.com/flatt-security/shisho-cloud-rego-libraries.git

mkdir ./your-policy
cd ./your-policy
```

At this point, you should have the following directory structure:

```bash
.
├── your-policy
└── shisho-cloud-rego-libraries
```

The final directory structure will be as follows:

```bash
.
├── your-policy
│   ├── implementation
│   │   ├── decide.rego
│   │   ├── decide_test.rego
│   │   ├── decide.graphql
│   │   └── manifest.yaml
|   ├── specification
│       └── dgspec.yaml
└── shisho-cloud-rego-libraries
```

  </TabItem>
  <TabItem value="typescript" label="TypeScript">

The inspection rule implementation uses [Deno](https://deno.com/) as the JavaScript/TypeScript runtime, so please refer to the [Deno official documentation](https://docs.deno.com/runtime/manual/getting_started/installation) to install Deno. It is also more convenient to install the [Deno plugin for your editor](https://docs.deno.com/runtime/manual/getting_started/setup_your_environment).

The library used to write policy code for Shisho Cloud is published as [shisho_cloud_policy_helpers](https://deno.land/x/shisho_cloud_policy_helpers). In Deno, you can directly reference the library in an import statement as shown below, so there is no need to install libraries, etc.

```typescript
import { DecisionPolicy } from "https://deno.land/x/shisho_cloud_policy_helpers/decision/mod.ts";
```

  </TabItem>
</Tabs>

## Define an inspection specification

First, let's define an inspection specification. An inspection specification is a definition of an inspection item in Shisho Cloud. The inspection specification is displayed in a location such as "A test security check" or "Top-level heading 1" in the screen example below, and is used to explain the background of the risk added on Shisho Cloud:

![](/docs/_md-assets/a07d33cd7e-finding.ja.png)

YAML is used to define the inspection specification.
Create a file named `./your-policy/specification/dgspec.yaml` and try to explain the outline of the inspection while following the instructions in the comments:

<CodeBlock language="yaml" title="./your-policy/specification/dgspec.yaml">
  {DgSpec}
</CodeBlock>

When you're done, run the following command to register the inspection specification with Shisho Cloud:

```bash
shishoctl dgspec apply -o $SHISHO_ORG_ID -f "your-policy/specification/dgspec.yaml"
```

Once the registration is complete, run the following command to verify that the inspection specification has been registered correctly:

```sh
$ shishoctl dgspec describe "user.decision.api.shisho.dev/v1" "my-security-review" -o $SHISHO_ORG_ID | jq -r
{
  "apiVersion": "user.decision.api.shisho.dev/v1",
  "kind": "my-security-review",
  "title": "A test security check",
  "explanationMarkdown": "This is a test explanation. You can use **Markdown** here.\n",
  "createdAt": "2023-11-13T19:05:41Z",
  "updatedAt": "2023-11-13T19:05:41Z"
}
```

This completes the definition of the inspection specification in Shisho Cloud.
Note that you can use Markdown in `explanation` and specify `explanation` with a file path in `dgspec.yaml`.
Here are some examples of definitions:

<CodeBlock language="yaml" title="./your-policy/specification/dgspec.yaml">
  {DgSpecFile}
</CodeBlock>

```yaml title="./your-policy/specification/explanation.md"
This is a test explanation. You can use **Markdown** here.
```

## Define the inspection target data

Now, let's actually implement the inspection using the inspection specification we just created.
As an example, here we will implement an inspection that reports a problem if the machine type of an instance of Google Compute Engine is `f1-micro`.

Replace `[oid]` in the following URL with your Shisho Cloud organization ID and access the Shisho Cloud GraphQL Playground:

```
https://cloud.shisho.dev/[oid]/playground/query
```

![](/docs/_md-assets/bb70f6ce29-playground.png)

Using the displayed Playground, you can see that in order to implement the inspection as described above, you can obtain the inspection target data in the following form:

<CodeBlock
  language="graphql"
  title="./your-policy/implementation/decide.graphql"
>
  {DecideGraphQL}
</CodeBlock>

## Implement the inspection

<Tabs groupId="policy-lang" queryString>
  <TabItem value="rego" label="Rego">

Once you can get the inspection target data, the next step is to implement the inspection.
If you want to report a problem if the instance machine type of Google Compute Engine is `f1-micro`, you can implement it in the following way, for example:

<CodeBlock language="rego" title="./your-policy/implementation/decide.rego">
  {DecideRego}
</CodeBlock>

Let's make the above implementation `./your-policy/implementation/decide.rego` and this time write test code as well.
Create a file named `./your-policy/implementation/decide_test.rego` and refer to the following to write test code for the policy code you have written:

<CodeBlock
  language="rego"
  title="./your-policy/implementation/decide_test.rego"
>
  {DecideTestRego}
</CodeBlock>

Running the test code shows that the implemented inspection seems to work correctly:

```sh
$ opa test ./your-policy ./shisho-cloud-rego-libraries
```

  </TabItem>
  <TabItem value="typescript" label="TypeScript" default>

Once the inspection target data can be retrieved, the type definition of the data is generated, and the inspection logic is implemented based on the type definition.

The TypeScript type definition corresponding to the GraphQL query earlier can be generated using the following command:

```bash
shishoctl codegen typescript-input --query-path=./your-policy/implementation/decide.graphql --output=./your-policy/implementation/input.gen.ts
```

When you run this command, the type `Input` representing the inspection target data will be defined as follows. This file contains not only the type itself but also documentation for each field, so it may be easier to refer to this `input.gen.ts` than the original GraphQL query when implementing inspection logic.

<CodeBlock
  language="typescript"
  title="./your-policy/implementation/input.gen.ts"
>
  {InputTS}
</CodeBlock>

Now that we have the type definition for the inspection target data, let's implement the function `decide`, which represents the inspection logic, using this type definition.
Let's name the file in which to implement this function `./your-policy/implementation/decide.ts`.

First, let's explicitly specify the type of the function `decide` as [`DecisionPolicy<Input>`](https://deno.land/x/shisho_cloud_policy_helpers/decision/mod.ts?s=DecisionPolicy), as shown below. This type represents a function that takes `Input` as input [^1] and returns an array of inspection results [`Decision[]`](https://deno.land/x/shisho_cloud_policy_helpers/decision/mod.ts?s=Decision).

[^1]: As an additional argument, you can pass [parameters](/docs/g/getting-started/optimize-your-workflows/parameter.md) passed from the workflow manifest.

```typescript title="./your-policy/implementation/decide.ts"
import { Input } from "./input.gen.ts";
import { DecisionPolicy } from "https://deno.land/x/shisho_cloud_policy_helpers@v0.0.1/decision/mod.ts";

// Basically the same as `const decide = (input: Input): Decision[] => { ... }`
const decide: DecisionPolicy<Input> = (input) => {
  /* TODO */
};
```

For this function to be executed on Shisho Cloud, you need to **default export** the **wrapper function `decision_policy_adapter`** with `decide` wrapped in it, as shown below. The wrapper function `decision_policy_adapter` should be given `convert_input` defined in `input.gen.ts` generated earlier as an argument.

```typescript title="./your-policy/implementation/decide.ts"
// highlight-next-line
import { convert_input, Input } from "./input.gen.ts";
// highlight-next-line
import {
  DecisionPolicy,
  decision_policy_adapter,
} from "https://deno.land/x/shisho_cloud_policy_helpers@v0.0.1/decision/mod.ts";

const decide: DecisionPolicy<Input> = (input) => {
  /* TODO */
};

// highlight-next-line
export default decision_policy_adapter(convert_input)(decide);
```

Now let's implement the body of the function `decide`. If you want to report a problem if the instance machine type of Google Compute Engine is `f1-micro`, you can implement it in the following way, for example:

<CodeBlock language="typescript" title="./your-policy/implementation/decide.ts">
  {DecideTS}
</CodeBlock>

Now that we have finished implementing the policy code, let's write the test code.
The testing strategy is to give some input to the `decide` function that represents the inspection logic and see if the output inspection result is as expected. Export `decide` in the previous `decide.ts` so that the test code can import the `decide` function.

```diff title="./your-policy/implementation/decide.ts"
-const decide: DecisionPolicy<Input> = (input) =>
+export const decide: DecisionPolicy<Input> = (input) =>
```

Now create a file named `./your-policy/implementation/decide_test.ts` and refer to the following to write test code for the policy code you have written:

<CodeBlock
  language="typescript"
  title="./your-policy/implementation/decide_test.ts"
>
  {DecideTestTS}
</CodeBlock>

Running the test code shows that the implemented inspection seems to work correctly:

```sh
$ deno test ./your-policy/implementation/decide_test.ts
Check file:///path/to/your-policy/implementation/decide_test.ts
running 1 test from ./your-policy/implementation/decide_test.ts
my policy works ... ok (0ms)

ok | 1 passed | 0 failed (1ms)
```

  </TabItem>
</Tabs>

## Define a workflow

As a final step, we define a workflow to execute the inspection logic we just implemented.
A workflow is a unit that groups inspections in Shisho Cloud, and contains a **trigger** that defines when the policy should be executed.

YAML is used to define the workflow.
Create a file named `./your-policy/implementation/manifest.yaml` and try to define a workflow by following the instructions in the comments:

<Tabs groupId="policy-lang" queryString>
  <TabItem value="rego" label="Rego">

<CodeBlock language="yaml" title="./your-policy/implementation/manifest.yaml">
  {ManifestRego}
</CodeBlock>

  </TabItem>
  <TabItem value="typescript" label="TypeScript">

<CodeBlock language="yaml" title="./your-policy/implementation/manifest.yaml">
  {ManifestTS}
</CodeBlock>

As a preparation for deploying this workflow, you need to download the libraries used by the policy code with the following command:

```bash
deno vendor $(find . -name '*.[jt]s' -not -path './vendor/*')
```

  </TabItem>
</Tabs>

## Deploy the workflow

Now, finally, let's deploy the completed workflow to Shisho Cloud.
Run the following command:

<Tabs groupId="policy-lang" queryString>

<TabItem value="rego" label="Rego">

```bash
shishoctl workflow apply -o $SHISHO_ORG_ID -f ./your-policy/implementation/manifest.yaml
```

</TabItem>

<TabItem value="typescript" label="TypeScript">

```bash
shishoctl workflow apply -o $SHISHO_ORG_ID -f ./your-policy/implementation/manifest.yaml --js-import-map=./vendor/import_map.json --workspace-root=.
```

</TabItem>

</Tabs>

Once the deployment is complete, you can run the workflow without waiting for the `schedule` trigger to fire by running a command like this:

```bash
shishoctl workflow run -o $SHISHO_ORG_ID my-review-workflow
```

After a while, the workflow execution will complete:

![](/docs/_md-assets/ea77d4469e-run.png)

When you check the details of the execution result and the inspection result, you can see that the instance with `f1-micro` is surely rejected:

![](/docs/_md-assets/87dd219f82-run-example.ja.png)

![](/docs/_md-assets/a07d33cd7e-finding.ja.png)

In this way, we were finally able to extend the inspection in Shisho Cloud!

## Summary

This tutorial explained how to extend the inspection capabilities provided by Shisho Cloud. Specifically, you practiced the following:

- Registering inspection specifications (**Specification**) with Shisho Cloud
- Writing and deploying Shisho Cloud policies
