# Managing Declarative Job Templates -- Deprecated [Declarative Job Templates](declarative-templates.md), currently a preview feature, allow a user to define a reusable fuzzing pipeline as a template. Once saved, any user of the OneFuzz instance can create fuzzing jobs based on the templates. This is a walk-through guide for updating an existing job template, though the process is similar for creating templates from scratch. This process demonstrates adding [Microsoft Teams notifications](notifications/teams.md) for new unique crash reports to an existing `libfuzzer_linux` job template and saving it as `libfuzzer_with_teams`. ## Using the CLI & modifying JSON 1. Enable support for declarative templates. ``` onefuzz config --enable_feature job_templates ``` 2. List available templates. ``` onefuzz job_templates list ```` 3. Save a copy of the template locally. ``` onefuzz job_templates manage get libfuzzer_linux > libfuzzer_linux.json ``` 3. With your preferred text editor, add the following to the `notifications` list: ```json { "container_type": "unique_reports", "notification": { "config": { "url": "https://contoso.com/webhook-url-here" } } } ``` 5. Upload the template. ``` onefuzz job_templates manage upload libfuzzer_with_teams @./libfuzzer_linux.json ``` > NOTE: Using @./filename allows specifying read the contents of a file, rather than specifying JSON on the command line. ## Using the SDK 1. Enable support for declarative templates. ``` onefuzz config --enable_feature job_templates ``` 2. Run the following python ```python from onefuzztypes.job_templates import JobTemplateNotification from onefuzztypes.models import NotificationConfig, TeamsTemplate from onefuzztypes.enums import ContainerType from onefuzz.api import Onefuzz o = Onefuzz() template = o.job_templates.manage.get("libfuzzer_linux") template.notifications.append( JobTemplateNotification( container_type=ContainerType.unique_reports, notification=NotificationConfig( config=TeamsTemplate(url="https://contoso.com/webhook-url-here") ), ) ) o.job_templates.manage.upload("libfuzzer_with_teams", template) ``` ## Using the updated template The OneFuzz SDK caches the list of Declarative Job Templates and will automatically refresh the templates every 24 hours. As shown below, users can refresh the declarative job template cache on demand. If an existing template is changed without requiring new user input via [form fields](declarative-templates.md#example-form-fields), using the template can happen transparently. If you create a new template or update an existing template that changes the user interaction, users will need to refresh their template cache to make use of the change. Now let's make use of our new template. 1. Update our template cache to make sure we have the latest `libfuzzer_with_teams` template ``` $ onefuzz job_templates refresh WARNING:onefuzz:job_templates are a preview-feature and may change in an upcoming release INFO:onefuzz:refreshing job template cache INFO:onefuzz:updated template definition: libfuzzer_linux INFO:onefuzz:updated template definition: libfuzzer_with_teams INFO:onefuzz:updated template definition: afl_windows INFO:onefuzz:updated template definition: afl_linux INFO:onefuzz:updated template definition: libfuzzer_windows $ ``` 2. Launch our job ``` $ onefuzz job_templates submit libfuzzer_with_teams example-project example-target build-1 linux --target_exe ./fuzz.exe WARNING:onefuzz:job_templates are a preview-feature and may change in an upcoming release INFO:onefuzz:creating container: oft-inputs-88dfb15b9ab758b88b122508d4648687 INFO:onefuzz:creating container: oft-readonly-inputs-88dfb15b9ab758b88b122508d4648687 INFO:onefuzz:creating container: oft-no-repro-88dfb15b9ab758b88b122508d4648687 INFO:onefuzz:creating container: oft-crashes-88dfb15b9ab758b88b122508d4648687 INFO:onefuzz:creating container: oft-reports-88dfb15b9ab758b88b122508d4648687 INFO:onefuzz:creating container: oft-unique-reports-88dfb15b9ab758b88b122508d4648687 INFO:onefuzz:creating container: oft-setup-fde90db8a8e65b4e8b7518f9d1350036 INFO:onefuzz:uploading ./fuzz.exe to oft-setup-fde90db8a8e65b4e8b7518f9d1350036 INFO:onefuzz:creating container: oft-coverage-88dfb15b9ab758b88b122508d4648687 { "config": { "build": "build-1", "duration": 24, "name": "example-target", "project": "example-project" }, "job_id": "d3259dfe-fdad-45a0-bf90-a381b8dc1ee8", "state": "init" } $ ``` 3. Verify a notification was set up for the unique reports container ``` $ onefuzz notifications list --query "[?container == 'oft-unique-reports-88dfb15b9ab758b88b122508d4648687']" [ { "config": { "url": "***" }, "container": "oft-unique-reports-88dfb15b9ab758b88b122508d4648687", "notification_id": "0e0c10a1-78ef-4f65-be56-d3ba0788fcb5" } ] ``` ## Adding a required field In many cases, we want users of the template to provide more detail, such as data that can be used to tailor the notifications based on the target at hand. This is accomplished via a [form fields](declarative-templates.md#example-form-fields). Let's make a new template that enables notifications via [Azure Devops Work Items](notifications/ado.md), where we require the user to specify the Area Path for the work items that OneFuzz will create. This example will demonstrate setting the following: * `Project` via a project name specified during job creation. * `Area Path` via a new required field. * `Iteration Path` via a new optional field, with a default value in the template. 1. Enable support for declarative templates. This is required because declarative templates are not yet stabilized. ``` onefuzz config --enable_feature job_templates ``` 2. Save a copy of the template locally. ``` onefuzz job_templates manage get libfuzzer_linux > libfuzzer_linux_ado_areapath.json ``` 3. With your preferred text editor, add the following to the `notifications` list: ```json { "container_type": "unique_reports", "notification": { "config": { "base_url": "https://dev.azure.com/", "auth_token": "ADO_AUTH_TOKEN", "type": "Bug", "project": "{{ job.project }}", "ado_fields": { "System.AreaPath": "{{ task.tags['area_path'] }}", "Microsoft.VSTS.Scheduling.StoryPoints": "1", "System.IterationPath": "{{ task.tags['iteration_path'] }}", "System.Title": "{{ report.crash_site }} - {{ report.executable }}", "Microsoft.VSTS.TCM.ReproSteps": "This is my call stack: " }, "comment": "This is my comment. {{ report.input_sha256 }} {{ input_url }}
{{ repro_cmd }}
", "unique_fields": ["System.Title", "System.AreaPath"], "on_duplicate": { "comment": "Another POC was found in target.
{{ repro_cmd }}
", "set_state": { "Resolved": "Active" }, "ado_fields": { "System.IterationPath": "{{ task.tags['iteration_path'] }}" }, "increment": ["Microsoft.VSTS.Scheduling.StoryPoints"] } } } } ``` > NOTE: The use of `task.tags` throughout the template. The next steps will define how values get assigned to this dictionary. 4. With your preferred text editor, add the following to user fields to the end of the `user_fields` list. 1. A required field that specifies the tag name `area_path`. ```json { "help": "Area path for reported crashes", "locations": [ { "op": "add", "path": "/tasks/1/tags/area_path" } ], "name": "area_path", "required": true, "type": "Str" } ``` 2. An optional field that specifies the `iteration_path` ```json { "default": "Iteration\\Path\\Default\\Here", "help": "Iteration path for reported crashes", "locations": [ { "op": "add", "path": "/tasks/1/tags/iteration_path" } ], "name": "iteration_path", "required": false, "type": "Str" } ``` > NOTE: Each of these fields use the `jsonpatch` path to add a tag to the second task (by array index), which is the `crash_report` task. Check out [form fields](declarative-templates.md#example-form-fields) for more information. 5. Upload the template. ``` onefuzz job_templates manage upload libfuzzer_linux_ado_areapath @./libfuzzer_linux_ado_areapath.json ``` > NOTE: Using @./filename allows specifying read the contents of a file, rather than specifying JSON on the command line. 6. Refresh the template cache. ``` onefuzz job_templates refresh ``` Using `--help`, we can see the new optional and required arguments. ``` $ onefuzz job_templates submit libfuzzer_linux_ado_areapath --help usage: onefuzz job_templates submit libfuzzer_linux_ado_areapath [-h] [-v] [--format {json,raw}] [--query QUERY] [--target_exe TARGET_EXE] [--duration DURATION] [--target_workers TARGET_WORKERS] [--vm_count VM_COUNT] [--target_options [TARGET_OPTIONS [TARGET_OPTIONS ...]]] [--target_env str=str [str=str ...]] [--reboot_after_setup] [--check_retry_count CHECK_RETRY_COUNT] [--target_timeout TARGET_TIMEOUT] [--mytags str=str [str=str ...]] [--iteration_path ITERATION_PATH] [--setup_dir SETUP_DIR] [--inputs_dir INPUTS_DIR] [--readonly_inputs_dir READONLY_INPUTS_DIR] [--container_names ContainerType=str [ContainerType=str ...]] [--parameters JobTemplateRequestParameters] project name build pool_name area_path ``` The new field, `area_path` is now a required argument and `iteration_path` is an optional argument. Let's create a job using this template and verify the tags are as we expect. Since the parameters we added only modify the `libfuzzer_crash_report` task, we'll search just for the that task. ``` $ onefuzz job_templates submit libfuzzer_linux_ado_areapath myproject myname build1 linux My\\Iteration\\Path WARNING:onefuzz:job_templates are a preview-feature and may change in an upcoming release INFO:onefuzz:creating container: oft-setup-cf346c84f2df551381d9991a5efbd030 INFO:onefuzz:uploading fuzz.exe to oft-setup-cf346c84f2df551381d9991a5efbd030 INFO:onefuzz:creating container: oft-unique-reports-71bdf0b1ce175a2796954f8d62f5d3d0 INFO:onefuzz:creating container: oft-reports-71bdf0b1ce175a2796954f8d62f5d3d0 INFO:onefuzz:creating container: oft-coverage-71bdf0b1ce175a2796954f8d62f5d3d0 INFO:onefuzz:creating container: oft-no-repro-71bdf0b1ce175a2796954f8d62f5d3d0 INFO:onefuzz:creating container: oft-inputs-71bdf0b1ce175a2796954f8d62f5d3d0 INFO:onefuzz:creating container: oft-crashes-71bdf0b1ce175a2796954f8d62f5d3d0 INFO:onefuzz:creating container: oft-readonly-inputs-71bdf0b1ce175a2796954f8d62f5d3d0 { "config": { "build": "build1", "duration": 24, "name": "myname", "project": "myproject" }, "job_id": "1eaa9a23-fcdb-400a-a26c-3ebe712fde53", "state": "init" } $ onefuzz jobs tasks list 1eaa9a23-fcdb-400a-a26c-3ebe712fde53 --query "[?config.task.type == 'libfuzzer_crash_report'].config.tags" [ { "area_path": "My\\Iteration\\Path", "iteration_path": "Iteration\\Path\\Default\\Here" } ] $ ``` As we can see, the tag `area_path` is the value we specified, and because we didn't specify `iteration_path`, it uses the default from the template.