From 0dbd5459bdae52062accd3f049acc6911c7ba788 Mon Sep 17 00:00:00 2001 From: Keshav Priyadarshi Date: Mon, 20 Oct 2025 20:00:50 +0530 Subject: [PATCH 1/3] Add config to run pipeline once Signed-off-by: Keshav Priyadarshi --- .../0110_pipelineschedule_is_run_once.py | 22 +++++++++++++++++++ vulnerabilities/models.py | 7 ++++++ vulnerabilities/pipelines/__init__.py | 8 +++++++ 3 files changed, 37 insertions(+) create mode 100644 vulnerabilities/migrations/0110_pipelineschedule_is_run_once.py diff --git a/vulnerabilities/migrations/0110_pipelineschedule_is_run_once.py b/vulnerabilities/migrations/0110_pipelineschedule_is_run_once.py new file mode 100644 index 000000000..e9265e2ae --- /dev/null +++ b/vulnerabilities/migrations/0110_pipelineschedule_is_run_once.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.22 on 2026-01-08 13:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("vulnerabilities", "0109_alter_advisoryseverity_scoring_elements_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="pipelineschedule", + name="is_run_once", + field=models.BooleanField( + db_index=True, + default=False, + help_text="When set to True, this Pipeline will run only once.", + ), + ), + ] diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 38f4ebdc3..02a3f4098 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -2273,6 +2273,13 @@ class PipelineSchedule(models.Model): ), ) + is_run_once = models.BooleanField( + null=False, + db_index=True, + default=False, + help_text=("When set to True, this Pipeline will run only once."), + ) + live_logging = models.BooleanField( null=False, db_index=True, diff --git a/vulnerabilities/pipelines/__init__.py b/vulnerabilities/pipelines/__init__.py index c642748b0..9efd58c05 100644 --- a/vulnerabilities/pipelines/__init__.py +++ b/vulnerabilities/pipelines/__init__.py @@ -169,6 +169,10 @@ class VulnerableCodeBaseImporterPipeline(VulnerableCodePipeline): importer_name = None advisory_confidence = MAX_CONFIDENCE + # When set to true pipeline is run only once. + # To rerun onetime pipeline reset is_active field to True via migration. + run_once = False + @classmethod def steps(cls): return ( @@ -262,6 +266,10 @@ class VulnerableCodeBaseImporterPipelineV2(VulnerableCodePipeline): repo_url = None ignorable_versions = [] + # When set to true pipeline is run only once. + # To rerun onetime pipeline reset is_active field to True via migration. + run_once = False + @classmethod def steps(cls): return ( From 11a96812e310e9a0593b49545d5e16f619c33e9a Mon Sep 17 00:00:00 2001 From: Keshav Priyadarshi Date: Fri, 9 Jan 2026 19:30:10 +0530 Subject: [PATCH 2/3] Deactivate onetime pipeline after first run - To rerun onetime pipeline, reset `is_active` to `True` via a migration, pipeline will run one more time and then deactivate. - To convert a onetime pipeline to a regular pipeline, set the `run_once` class variable to `False` and reset the `is_active` field to `True` via a migration. Signed-off-by: Keshav Priyadarshi --- .../management/commands/run_scheduler.py | 25 +++++++++++-------- vulnerabilities/schedules.py | 16 +++++++++--- vulnerabilities/tasks.py | 8 +++++- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/vulnerabilities/management/commands/run_scheduler.py b/vulnerabilities/management/commands/run_scheduler.py index f7583ed41..476eb4816 100644 --- a/vulnerabilities/management/commands/run_scheduler.py +++ b/vulnerabilities/management/commands/run_scheduler.py @@ -17,16 +17,21 @@ def init_pipeline_scheduled(): - """Initialize schedule jobs for active PipelineSchedule.""" - active_pipeline_qs = models.PipelineSchedule.objects.filter(is_active=True).order_by( - "created_date" - ) - for pipeline_schedule in active_pipeline_qs: - if scheduled_job_exists(pipeline_schedule.schedule_work_id): - continue - new_id = pipeline_schedule.create_new_job() - pipeline_schedule.schedule_work_id = new_id - pipeline_schedule.save(update_fields=["schedule_work_id"]) + """ + Initialize schedule jobs for active PipelineSchedule. + - Create new schedule if there is no schedule for active pipeline + - Create new schedule if schedule is corrupted for an active pipeline + - Delete schedule for inactive pipeline + """ + pipeline_qs = models.PipelineSchedule.objects.order_by("created_date") + for pipeline in pipeline_qs: + reset_schedule = pipeline.is_active != bool(pipeline.schedule_work_id) + if not scheduled_job_exists(pipeline.schedule_work_id): + reset_schedule = True + + if reset_schedule: + pipeline.schedule_work_id = pipeline.create_new_job() + pipeline.save(update_fields=["schedule_work_id"]) class Command(rqscheduler.Command): diff --git a/vulnerabilities/schedules.py b/vulnerabilities/schedules.py index 2c2e5366b..8ae3bbb93 100644 --- a/vulnerabilities/schedules.py +++ b/vulnerabilities/schedules.py @@ -89,7 +89,15 @@ def update_pipeline_schedule(): from vulnerabilities.improvers import IMPROVERS_REGISTRY from vulnerabilities.models import PipelineSchedule - pipeline_ids = [*IMPORTERS_REGISTRY.keys(), *IMPROVERS_REGISTRY.keys()] - - PipelineSchedule.objects.exclude(pipeline_id__in=pipeline_ids).delete() - [PipelineSchedule.objects.get_or_create(pipeline_id=id) for id in pipeline_ids] + pipelines = IMPORTERS_REGISTRY | IMPROVERS_REGISTRY + + PipelineSchedule.objects.exclude(pipeline_id__in=pipelines.keys()).delete() + for id, pipeline_class in pipelines.items(): + run_once = getattr(pipeline_class, "run_once", False) + + PipelineSchedule.objects.get_or_create( + pipeline_id=id, + defaults={ + "is_run_once": run_once, + }, + ) diff --git a/vulnerabilities/tasks.py b/vulnerabilities/tasks.py index e035985a2..2e7ac2b10 100644 --- a/vulnerabilities/tasks.py +++ b/vulnerabilities/tasks.py @@ -17,7 +17,6 @@ from vulnerabilities import models from vulnerabilities.importer import Importer from vulnerabilities.improver import Improver -from vulnerablecode.settings import VULNERABLECODE_PIPELINE_TIMEOUT logger = logging.getLogger(__name__) @@ -48,6 +47,13 @@ def execute_pipeline(pipeline_id, run_id): exitcode = 1 run.set_run_ended(exitcode=exitcode, output=output) + + # Onetime pipeline are inactive after first execution. + pipeline = run.pipeline + if pipeline.is_run_once: + pipeline.is_active = False + pipeline.save() + logger.info("Update Run instance with exitcode, output, and end_date") From 68c080256891bbd14436ddb5210a891df6644e02 Mon Sep 17 00:00:00 2001 From: Keshav Priyadarshi Date: Fri, 9 Jan 2026 19:42:50 +0530 Subject: [PATCH 3/3] Use updated URLs for contribution guidelines Signed-off-by: Keshav Priyadarshi --- docs/source/contributing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index ba634ecc8..1258ae687 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -17,7 +17,7 @@ resources to help you get started. Do Your Homework ---------------- -Before adding a contribution or create a new issue, take a look at the project’s +Before adding a contribution or create a new issue, take a look at the project's `README `_, read through our `documentation `_, and browse existing `issues `_, @@ -73,7 +73,7 @@ overlooked. We value any suggestions to improve .. tip:: Our documentation is treated like code. Make sure to check our - `writing guidelines `_ + `writing guidelines `_ to help guide new users. Other Ways @@ -87,7 +87,7 @@ questions, and interact with us and other community members on Helpful Resources ----------------- -- Review our `comprehensive guide `_ +- Review our `comprehensive guide `_ for more details on how to add quality contributions to our codebase and documentation - Check this free resource on `How to contribute to an open source project on github `_ - Follow `this wiki page `_