)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"c0b13157e74efc95766d8cfc9f001c9c507aa2c3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"67fded93_036279d6","updated":"2026-07-23 13:44:53.000000000","message":"This review can be postponed after the core funcionality is proposed and reviewed","commit_id":"d91bfc806f23a42a606deaac5bd0d85f378f7ef0"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"563500ada84aca40633e0ffa635cd04c293b3601","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"d5b41294_8b1a8861","updated":"2026-08-04 10:34:55.000000000","message":"not yet ready for review","commit_id":"a8c521110b66efb389c82475714fd01006eb7775"}],"api-ref/source/samples/auditpipeline-create-response.json":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"fc83daf4caff3fd88f55cefc4c5f23b626b174b3","unresolved":false,"context_lines":[{"line_number":27,"context_line":"            \"created_at\": \"2026-07-14T10:00:00+00:00\","},{"line_number":28,"context_line":"            \"updated_at\": null,"},{"line_number":29,"context_line":"            \"deleted_at\": null,"},{"line_number":30,"context_line":"            \"links\": ["},{"line_number":31,"context_line":"                {"},{"line_number":32,"context_line":"                    \"rel\": \"self\","},{"line_number":33,"context_line":"                    \"href\": \"http://controller:9322/v1/audit_pipeline_stages/11111111-1111-1111-1111-111111111111\""}],"source_content_type":"application/json","patch_set":12,"id":"3d7fa437_cf4ecf13","line":30,"updated":"2026-08-21 19:44:18.000000000","message":"The auditpipeline create/show/update/cancel response samples each embed a \u0027links\u0027 array inside every stage object with hrefs to /v1/audit_pipeline_stages/{uuid}, but the AuditPipelineStage wsme type declares no links attribute and no stage controller or route exists, so real API responses never contain stage links.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Clients generated from or validated against the api-ref will expect per-stage links and a stage sub-resource endpoint that do not exist, breaking integrations and SDK validation.\n\n**Suggestion**:\nRemove the \u0027links\u0027 arrays from each stage object in auditpipeline-create/show/update/cancel-response.json while keeping the pipeline-level links; alternatively add stage links only if a stage endpoint is introduced later.","commit_id":"12915584484ccbab32bf63743a23513383cd06b9"}],"api-ref/source/watcher-api-v1-actionplans.inc":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"ae44f94143bfbc571e3876b5178d37348603444a","unresolved":false,"context_lines":[{"line_number":77,"context_line":""},{"line_number":78,"context_line":".. rest_parameters:: parameters.yaml"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"   - audit_uuid: r_audit"},{"line_number":81,"context_line":"   - strategy: r_strategy"},{"line_number":82,"context_line":"   - limit: limit"},{"line_number":83,"context_line":"   - marker: marker"}],"source_content_type":"text/x-c++src","patch_set":9,"id":"bb9f2dce_dcf7f33f","line":80,"updated":"2026-08-18 14:55:04.000000000","message":"get_all and detail for action plans now accept an audit_pipeline_uuid query parameter (action_plan.py:512, :559) that filters plans by owning pipeline at microversion \u003e\u003d 1.8. The api-ref \u0027List Action Plan\u0027 and \u0027List Action Plan Detailed\u0027 request sections were not updated: they still list only audit_uuid, strategy, limit, marker, sort_dir, sort_key, and no in:query parameter named for audit_pipeline_uuid exists in parameters.yaml (only the in:body actionplan_audit_pipeline_uuid entry at parameters.yaml:219).\n\n**Severity**: SUGGESTION | **Confidence**: 0.85\n\n**Impact**: API consumers reading the reference cannot discover the supported filter for pipeline-created plans, reducing discoverability of the 1.8 feature the commit documents elsewhere.\n\n**Recommendation**:\nAdd an in:query audit_pipeline_uuid parameter to parameters.yaml (min_version: 1.8) and reference it in the List Action Plan and List Action Plan Detailed request rest_parameters blocks of watcher-api-v1-actionplans.inc, mirroring how audit_uuid/r_audit is documented.","commit_id":"12947a616551baab64f5771cac2e1ca5db3be438"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"12080d960ef549af9d74a312988ffdc8dc9a1d1d","unresolved":false,"context_lines":[{"line_number":77,"context_line":""},{"line_number":78,"context_line":".. rest_parameters:: parameters.yaml"},{"line_number":79,"context_line":""},{"line_number":80,"context_line":"   - audit_uuid: r_audit"},{"line_number":81,"context_line":"   - strategy: r_strategy"},{"line_number":82,"context_line":"   - limit: limit"},{"line_number":83,"context_line":"   - marker: marker"}],"source_content_type":"text/x-c++src","patch_set":9,"id":"d6084fd1_9bc43ec9","line":80,"in_reply_to":"bb9f2dce_dcf7f33f","updated":"2026-08-19 20:13:20.000000000","message":"Ack, updated in next PS","commit_id":"12947a616551baab64f5771cac2e1ca5db3be438"}],"watcher/api/controllers/v1/action_plan.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"ae44f94143bfbc571e3876b5178d37348603444a","unresolved":false,"context_lines":[{"line_number":471,"context_line":"            filters\u003dfilters,"},{"line_number":472,"context_line":"        )"},{"line_number":473,"context_line":""},{"line_number":474,"context_line":"        if not api_utils.allow_audit_pipeline():"},{"line_number":475,"context_line":"            action_plans \u003d ["},{"line_number":476,"context_line":"                ap for ap in action_plans if ap.audit_pipeline_id is None"},{"line_number":477,"context_line":"            ]"}],"source_content_type":"text/x-python","patch_set":9,"id":"0f2af63f_7c2e32f2","line":474,"updated":"2026-08-18 14:55:04.000000000","message":"In _get_action_plans_collection, at microversion \u003c 1.8 the DB returns up to \u0027limit\u0027 action plans, then pipeline-created plans are removed with an in-Python list comprehension before ActionPlanCollection.convert_with_links computes the \u0027next\u0027 link. Collection.has_next() (watcher/api/controllers/v1/collection.py:35) only returns a next link when len(collection) \u003d\u003d limit, so any page containing at least one pipeline-created plan comes back shorter than limit and has_next() returns False. The client gets no \u0027next\u0027 link and silently stops paging, even though more non-pipeline plans exist beyond that page.\n\n**Severity**: WARNING | **Confidence**: 0.85\n\n**Impact**: After an upgrade, any existing client pinned below 1.8 that lists action plans with a limit will receive silently truncated result sets (missing non-pipeline action plans) whenever a pipeline-created plan lands inside a fetched page. Results are dropped without any error indication.\n\n**Suggestion**:\nExclude pipeline-created plans server-side instead: when api_utils.allow_audit_pipeline() is false, pass a filter (e.g. filters[\u0027audit_pipeline_id\u0027] \u003d None / an IS NULL variant) into objects.ActionPlan.list so limit/marker/next-link stay consistent; alternatively compute the \u0027next\u0027 marker from the unfiltered page. Add a test with limit\u003d1 and a pipeline plan preceding a regular plan asserting the next link still appears at \u003c1.8.","commit_id":"12947a616551baab64f5771cac2e1ca5db3be438"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"12080d960ef549af9d74a312988ffdc8dc9a1d1d","unresolved":false,"context_lines":[{"line_number":471,"context_line":"            filters\u003dfilters,"},{"line_number":472,"context_line":"        )"},{"line_number":473,"context_line":""},{"line_number":474,"context_line":"        if not api_utils.allow_audit_pipeline():"},{"line_number":475,"context_line":"            action_plans \u003d ["},{"line_number":476,"context_line":"                ap for ap in action_plans if ap.audit_pipeline_id is None"},{"line_number":477,"context_line":"            ]"}],"source_content_type":"text/x-python","patch_set":9,"id":"357f313d_c035904a","line":474,"in_reply_to":"0f2af63f_7c2e32f2","updated":"2026-08-19 20:13:20.000000000","message":"Fixed in next PS","commit_id":"12947a616551baab64f5771cac2e1ca5db3be438"}],"watcher/api/controllers/v1/audit_pipeline.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"aad0c52589a9819e03da5c382ae55a3917e38f28","unresolved":false,"context_lines":[{"line_number":741,"context_line":""},{"line_number":742,"context_line":"        PENDING pipelines are cancelled immediately. ONGOING pipelines"},{"line_number":743,"context_line":"        are transitioned to CANCELLED so the decision engine can detect"},{"line_number":744,"context_line":"        and stop execution. Returns 409 if the pipeline is already in a"},{"line_number":745,"context_line":"        terminal state (SUCCEEDED or FAILED)."},{"line_number":746,"context_line":""},{"line_number":747,"context_line":"        :param audit_pipeline_uuid: UUID of an audit pipeline."}],"source_content_type":"text/x-python","patch_set":1,"id":"707f5ab5_3b99e7c9","line":744,"updated":"2026-07-15 17:24:07.000000000","message":"The cancel and delete method docstrings in audit_pipeline.py state that terminal-state and ONGOING rejections return HTTP 409, but the methods raise exception.Invalid (and DeleteError, a subclass of Invalid) which maps to HTTP 400 BAD_REQUEST.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: API consumers reading the docstrings may implement incorrect error-handling logic expecting HTTP 409 (Conflict) when they will actually receive HTTP 400 (Bad Request). This could cause client retry or error-handling code to behave unexpectedly.\n\n**Suggestion**:\nUpdate the cancel docstring to say \u0027Returns 400 if the pipeline is already in a terminal state\u0027 and the delete docstring to say \u0027Returns 400 if the pipeline is ONGOING\u0027. Alternatively, if 409 is semantically preferred, raise exception.Conflict instead, but note that the existing audit delete uses DeleteError (400) so 400 is consistent with project conventions.","commit_id":"d91bfc806f23a42a606deaac5bd0d85f378f7ef0"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"dcc33c4df8f9ba0e69c020111d999189c1892f0b","unresolved":false,"context_lines":[{"line_number":21,"context_line":"and produces an combined :ref:`Action Plan \u003caction_plan_definition\u003e`. The"},{"line_number":22,"context_line":"pipeline is designed for ONESHOT execution."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Clients using API microversion \u003c 1.8 cannot access Audit Pipeline resources."},{"line_number":25,"context_line":"\"\"\""},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"from http import HTTPStatus"}],"source_content_type":"text/x-python","patch_set":2,"id":"e23d37b1_21e4826e","line":24,"updated":"2026-08-03 22:39:26.000000000","message":"The audit_pipeline.py module docstring states \u0027Clients using API microversion \u003c 1.8 cannot access Audit Pipeline resources.\u0027 However, no api_utils.allow_audit_pipeline() check exists in any controller method. All endpoints (get_all, get_one, detail, post, put, start, cancel, delete) are fully fun...\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Clients at microversion \u003c 1.7 can discover and use audit pipeline endpoints despite the documentation stating they cannot. While the V1 root hides the discovery link, the endpoints themselves are accessible, contradicting the documented contract.\n\n**Suggestion**:\nEither add allow_audit_pipeline() version gates to the controller methods (raising HTTPNotFound for \u003c 1.8, matching the action_plan pattern), or correct the module docstring to accurately describe that the endpoints are accessible at all versions but only discoverable via links at \u003e\u003d 1.8.","commit_id":"a8c521110b66efb389c82475714fd01006eb7775"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"dcc33c4df8f9ba0e69c020111d999189c1892f0b","unresolved":false,"context_lines":[{"line_number":628,"context_line":"            auto_trigger\u003dpipeline_body.auto_trigger or False,"},{"line_number":629,"context_line":"            state\u003dap_objects.State.PENDING,"},{"line_number":630,"context_line":"        )"},{"line_number":631,"context_line":"        new_pipeline.create()"},{"line_number":632,"context_line":""},{"line_number":633,"context_line":"        for i, (template, stage_input) in enumerate(resolved_stages):"},{"line_number":634,"context_line":"            stage \u003d objects.AuditPipelineStage("}],"source_content_type":"text/x-python","patch_set":2,"id":"4c71cacc_4225da7b","line":631,"updated":"2026-08-03 22:39:26.000000000","message":"The post() method creates the pipeline object, then creates each stage in a loop. If any stage.create() fails (e.g., DB error, constraint violation), the pipeline persists in the database with an incomplete set of stages. No rollback, cleanup, or transaction wrapping is performed.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: A failed stage creation leaves an orphaned pipeline with incomplete stages in the database. Subsequent operations on this pipeline (start, trigger) will produce unpredictable behavior since the pipeline definition is incomplete.\n\n**Suggestion**:\nWrap the pipeline and stage creation in a single DB transaction so that a failure in any stage creation rolls back the pipeline. Alternatively, add a try/except that deletes the pipeline (and any partially-created stages) if stage creation fails.","commit_id":"a8c521110b66efb389c82475714fd01006eb7775"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"dcc33c4df8f9ba0e69c020111d999189c1892f0b","unresolved":false,"context_lines":[{"line_number":741,"context_line":""},{"line_number":742,"context_line":"        PENDING pipelines are cancelled immediately. ONGOING pipelines"},{"line_number":743,"context_line":"        are transitioned to CANCELLED so the decision engine can detect"},{"line_number":744,"context_line":"        and stop execution. Returns 409 if the pipeline is already in a"},{"line_number":745,"context_line":"        terminal state (SUCCEEDED or FAILED)."},{"line_number":746,"context_line":""},{"line_number":747,"context_line":"        :param audit_pipeline_uuid: UUID of an audit pipeline."}],"source_content_type":"text/x-python","patch_set":2,"id":"e4ef7eae_e33159f6","line":744,"updated":"2026-08-03 22:39:26.000000000","message":"The cancel() method docstring says \u0027Returns 409 if the pipeline is already in a terminal state\u0027 and the delete() docstring says \u0027Returns 409 if the pipeline is ONGOING.\u0027 Both raise exception.Invalid or exception.DeleteError, which inherit from Invalid with code\u003dHTTPStatus.BAD_REQUEST (400). Tests...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: API consumers relying on docstrings to handle 409 Conflict responses will miss the actual 400 Bad Request errors, leading to incorrect error handling logic in client code.\n\n**Suggestion**:\nUpdate the cancel() and delete() docstrings to say \u0027Returns 400\u0027 instead of \u0027Returns 409\u0027. Alternatively, if 409 Conflict is the intended semantic (resource state conflict), use an appropriate exception that maps to HTTP 409.","commit_id":"a8c521110b66efb389c82475714fd01006eb7775"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"61f8d4fa87a757653d55b4952fe6db562189f97b","unresolved":false,"context_lines":[{"line_number":273,"context_line":"        stage.audit_pipeline_id \u003d wtypes.Unset"},{"line_number":274,"context_line":"        stage.goal_id \u003d wtypes.Unset"},{"line_number":275,"context_line":"        stage.strategy_id \u003d wtypes.Unset"},{"line_number":276,"context_line":"        stage.links \u003d ["},{"line_number":277,"context_line":"            link.Link.make_link("},{"line_number":278,"context_line":"                \u0027self\u0027, url, \u0027audit_pipeline_stages\u0027, stage.uuid"},{"line_number":279,"context_line":"            ),"}],"source_content_type":"text/x-python","patch_set":3,"id":"0ccb6c93_81a380c8","line":276,"updated":"2026-08-07 20:16:22.000000000","message":"The _convert_with_links method in AuditPipelineStage creates \u0027self\u0027 and \u0027bookmark\u0027 links pointing to the resource name \u0027audit_pipeline_stages\u0027, but no such REST controller is registered in the V1 Controller class. Only \u0027audit_pipelines\u0027 is registered. Any client following these stage links will r...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Clients consuming the \u0027self\u0027 or \u0027bookmark\u0027 link from any stage object in a pipeline detail or show response will get a 404 Not Found. The links are present in every stage representation returned by the API.\n\n**Suggestion**:\nEither register an AuditPipelineStagesController (even a read-only one) or remove the links from AuditPipelineStage since stages are only returned as embedded sub-resources of pipelines. If stages are not independently addressable, omitting links or using the parent pipeline URL is the cleanest approach.","commit_id":"9e8c708a507f07c91b0dc135186d46714d68d5be"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"32afd6d0407e881668c9244c88683f1a9b75588e","unresolved":false,"context_lines":[{"line_number":710,"context_line":"            action\u003d\u0027audit_pipeline:cancel\u0027,"},{"line_number":711,"context_line":"        )"},{"line_number":712,"context_line":""},{"line_number":713,"context_line":"        if pipeline.state in ("},{"line_number":714,"context_line":"            ap_objects.State.SUCCEEDED,"},{"line_number":715,"context_line":"            ap_objects.State.FAILED,"},{"line_number":716,"context_line":"        ):"}],"source_content_type":"text/x-python","patch_set":4,"id":"fd03a698_112adb9f","line":713,"updated":"2026-08-12 13:31:37.000000000","message":"The cancel method only rejects SUCCEEDED and FAILED states. An already-CANCELLED pipeline can be cancelled again (no-op returning 202), and a DELETED pipeline can be transitioned back to CANCELLED, which violates the state machine defined in AuditPipelineStateTransitionManager.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Canceling a DELETED pipeline would incorrectly change its state from DELETED back to CANCELLED, corrupting the state machine. Re-cancelling a CANCELLED pipeline is a confusing no-op that returns 202 Accepted without any actual state change.\n\n**Suggestion**:\nRestrict the cancel guard to only allow PENDING and ONGOING states, or use the AuditPipelineStateTransitionManager.check_transition() to validate the state change. Reject all other states with 409 Conflict.","commit_id":"b4e18054d4dcac23d2a0aca60d6b345e02261db8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"7c8365cd07712edd99cbddee70cc865562844996","unresolved":false,"context_lines":[{"line_number":273,"context_line":"        stage.audit_pipeline_id \u003d wtypes.Unset"},{"line_number":274,"context_line":"        stage.goal_id \u003d wtypes.Unset"},{"line_number":275,"context_line":"        stage.strategy_id \u003d wtypes.Unset"},{"line_number":276,"context_line":"        stage.links \u003d ["},{"line_number":277,"context_line":"            link.Link.make_link("},{"line_number":278,"context_line":"                \u0027self\u0027, url, \u0027audit_pipeline_stages\u0027, stage.uuid"},{"line_number":279,"context_line":"            ),"}],"source_content_type":"text/x-python","patch_set":6,"id":"d1f3dd43_49f87883","line":276,"updated":"2026-08-12 23:36:57.000000000","message":"AuditPipelineStage._convert_with_links() generates self and bookmark links using \u0027audit_pipeline_stages\u0027 as the resource name. However, no AuditPipelineStagesController is registered in the v1 Controller class, so the URL /v1/audit_pipeline_stages/{uuid} returns 404. Every API response that inclu...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: API clients following the self/bookmark links on stage objects will receive 404 errors. This breaks REST discoverability and HATEOAS compliance for the new API.\n\n**Suggestion**:\nEither register an AuditPipelineStagesController route, or change the link resource to reference the parent pipeline (e.g., \u0027audit_pipelines/{pipeline_uuid}/stages/{stage_uuid}\u0027). If stages are only accessible through the parent pipeline, consider omitting separate self/bookmark links or documenting that stages are sub-resources.","commit_id":"0e41ce5bc3e29b7ee72721cb7f23b13c3cf904c5"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"1a7c8d114a6285e2a37da9b2793ae114a5fff8a3","unresolved":true,"context_lines":[{"line_number":273,"context_line":"        stage.audit_pipeline_id \u003d wtypes.Unset"},{"line_number":274,"context_line":"        stage.goal_id \u003d wtypes.Unset"},{"line_number":275,"context_line":"        stage.strategy_id \u003d wtypes.Unset"},{"line_number":276,"context_line":"        stage.links \u003d ["},{"line_number":277,"context_line":"            link.Link.make_link("},{"line_number":278,"context_line":"                \u0027self\u0027, url, \u0027audit_pipeline_stages\u0027, stage.uuid"},{"line_number":279,"context_line":"            ),"}],"source_content_type":"text/x-python","patch_set":6,"id":"3e9e24c0_eff58b8f","line":276,"in_reply_to":"d1f3dd43_49f87883","updated":"2026-08-13 18:26:04.000000000","message":"Correct, doesn not make sense to provide bookmark links to audit pipeline stages, since is a sub-resource that we still don\u0027t support direct access.","commit_id":"0e41ce5bc3e29b7ee72721cb7f23b13c3cf904c5"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"7c8365cd07712edd99cbddee70cc865562844996","unresolved":false,"context_lines":[{"line_number":624,"context_line":"            auto_trigger\u003dpipeline_body.auto_trigger or False,"},{"line_number":625,"context_line":"            state\u003dap_objects.State.PENDING,"},{"line_number":626,"context_line":"        )"},{"line_number":627,"context_line":"        new_pipeline.create()"},{"line_number":628,"context_line":""},{"line_number":629,"context_line":"        for i, (template, stage_input) in enumerate(resolved_stages):"},{"line_number":630,"context_line":"            stage \u003d objects.AuditPipelineStage("}],"source_content_type":"text/x-python","patch_set":6,"id":"676d8e4b_dbf485dc","line":627,"updated":"2026-08-12 23:36:57.000000000","message":"The post() method creates the pipeline object first, then iterates over resolved_stages calling stage.create() for each. If any stage creation fails (DB error, constraint violation, etc.), the pipeline and any already-created stages remain in the database with no cleanup. There is no try/except a...\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: A failed pipeline creation leaves orphaned pipeline and partial stage records in PENDING state, which will accumulate over time and may confuse the decision engine when it processes the trigger_audit_pipeline RPC for a pipeline whose stages are incomplete.\n\n**Priority**: Before merge\n**Why This Matters**: A failed pipeline creation leaves orphaned pipeline and partial stage records in PENDING state, which will accumulate over time and may confuse the decision engine when it processes the trigger_audit_pipeline RPC for a pipeline whose stages are incomplete.\n\n**Recommendation**:\nWrap the stage creation loop in a try/except that soft-deletes or destroys the pipeline (and any created stages) on failure, re-raising the original exception afterward. Alternatively, create all records within a single DB transaction.","commit_id":"0e41ce5bc3e29b7ee72721cb7f23b13c3cf904c5"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"1a7c8d114a6285e2a37da9b2793ae114a5fff8a3","unresolved":true,"context_lines":[{"line_number":624,"context_line":"            auto_trigger\u003dpipeline_body.auto_trigger or False,"},{"line_number":625,"context_line":"            state\u003dap_objects.State.PENDING,"},{"line_number":626,"context_line":"        )"},{"line_number":627,"context_line":"        new_pipeline.create()"},{"line_number":628,"context_line":""},{"line_number":629,"context_line":"        for i, (template, stage_input) in enumerate(resolved_stages):"},{"line_number":630,"context_line":"            stage \u003d objects.AuditPipelineStage("}],"source_content_type":"text/x-python","patch_set":6,"id":"cbd81faf_0aa1c9cf","line":627,"in_reply_to":"676d8e4b_dbf485dc","updated":"2026-08-13 18:26:04.000000000","message":"Ack, we need an extra try/except to treat this scenario and delete the audit pipeline and previous stages","commit_id":"0e41ce5bc3e29b7ee72721cb7f23b13c3cf904c5"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"9c3dcf02910f21854033b535310fac15c163371c","unresolved":false,"context_lines":[{"line_number":390,"context_line":"        return sample"},{"line_number":391,"context_line":""},{"line_number":392,"context_line":""},{"line_number":393,"context_line":"class AuditPipelinesController(rest.RestController):"},{"line_number":394,"context_line":"    \"\"\"REST controller for Audit Pipelines.\"\"\""},{"line_number":395,"context_line":""},{"line_number":396,"context_line":"    def __init__(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"40581bdb_297bc833","line":393,"updated":"2026-08-13 20:21:58.000000000","message":"None of the seven REST endpoints in AuditPipelinesController check allow_audit_pipeline(), so they are accessible at any API microversion including \u003c 1.8. The module docstring explicitly promises the opposite: \u0027Clients using API microversion \u003c 1.8 cannot access Audit Pipeline resources.\u0027\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: A client sending requests without the OpenStack-API-Version header (defaulting to 1.0) can create, list, update, cancel, and delete audit pipelines. This violates the microversion contract, could confuse clients that do not expect these resources, and undermines the API version negotiation promise.\n\n**Suggestion**:\nAdd a microversion check at the start of each endpoint method (or use a shared decorator/helper), raising exception.NotAcceptable when allow_audit_pipeline() returns False, mirroring the data_model.py pattern at line 127.","commit_id":"7fcc2ada06110676158dcc1533d3a46e1f12becf"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"875c175e1fd63d05db45d85bd2f988ac6ac783ef","unresolved":false,"context_lines":[{"line_number":315,"context_line":"        return [AuditPipelineStage.convert_with_links(s) for s in stages]"},{"line_number":316,"context_line":""},{"line_number":317,"context_line":"    @staticmethod"},{"line_number":318,"context_line":"    def _convert_with_links(pipeline, url, expand\u003dTrue):"},{"line_number":319,"context_line":"        context \u003d pecan.request.context"},{"line_number":320,"context_line":"        pipeline.stage_uuids \u003d AuditPipeline._get_stage_uuids("},{"line_number":321,"context_line":"            pipeline.uuid, context"}],"source_content_type":"text/x-python","patch_set":10,"id":"05dce9b4_9c7139f7","line":318,"updated":"2026-08-19 21:23:46.000000000","message":"AuditPipeline._convert_with_links (audit_pipeline.py:318-337) calls _get_stage_uuids and _get_stages, each executing an identical AuditPipelineStage.list DB query with the same filters; in expand mode both run. Additionally, each AuditPipelineStage built via convert_with_links -\u003e __init__ triggers up to five more DB fetches: _set_audit_pipeline_uuid resolves the parent pipeline by id, and goal_uuid/goal_name each call objects.Goal.get while strategy_uuid/strategy_name each call objects.Strategy.get (audit_pipeline.py:144-239, 259-267). A GET /v1/audit_pipelines/{uuid} (expand\u003dTrue) or /v1/audit_pipelines/detail with N pipelines of S stages costs roughly 2 + N*(2 + 5*S) queries (e.g. ~52 queries for one 10-stage pipeline), and the plain list endpoint still pays one stage query per pipeline for stage_uuids.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Per-request DB load grows linearly with pipelines*stages on detail endpoints (5x redundant lookups per stage, 2x duplicate stage-list query per pipeline), degrading API latency and DB load as pipelines accumulate.\n\n**Suggestion**:\nIn _convert_with_links fetch the stage list once, derive stage_uuids from it, and build AuditPipelineStage objects from that single result; resolve each stage\u0027s goal/strategy once (e.g. eager-load or cache the Goal/Strategy per stage) instead of resolving uuid and name independently.","commit_id":"6031308bd2fc5c7a9c2a6a3876b830712a6c2262"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"875c175e1fd63d05db45d85bd2f988ac6ac783ef","unresolved":false,"context_lines":[{"line_number":594,"context_line":""},{"line_number":595,"context_line":"        new_pipeline \u003d objects.AuditPipeline("},{"line_number":596,"context_line":"            context,"},{"line_number":597,"context_line":"            name\u003dpipeline_body.name"},{"line_number":598,"context_line":"            if pipeline_body.name not in (wtypes.Unset, None)"},{"line_number":599,"context_line":"            else None,"},{"line_number":600,"context_line":"            audit_type\u003dpipeline_body.audit_type,"}],"source_content_type":"text/x-python","patch_set":10,"id":"62165cbc_380dc636","line":597,"updated":"2026-08-19 21:23:46.000000000","message":"POST /v1/audit_pipelines accepts an omitted \u0027name\u0027 (AuditPipelinePostType.name is mandatory\u003dFalse) and the controller persists name\u003dNone (audit_pipeline.py:597-599). The pre-existing DB layer create_audit_pipeline (watcher/db/sqlalchemy/api.py:866-870) runs a pre-check `query.filter_by(name\u003dvalues.get(\u0027name\u0027), deleted_at\u003dNone)`; with name\u003dNone SQLAlchemy renders `name IS NULL`, so once any unnamed pipeline exists the count check trips and raises AuditPipelineAlreadyExists. The schema\u0027s unique constraint `uniq_audit_pipelines0name` does not actually constrain NULL names, so this is a false conflict on valid input, and the 409 message references \u0027None\u0027 as the conflicting name.\n\n**Severity**: WARNING | **Confidence**: 0.85\n\n**Impact**: Only one pipeline without a name can ever be created per deployment; every further nameless POST returns 409 with a confusing \u0027None already exists\u0027 message even though no duplicate exists.\n\n**Suggestion**:\nEither make \u0027name\u0027 mandatory in AuditPipelinePostType, or skip the name-uniqueness pre-check (and rely on the constraint) when values.get(\u0027name\u0027) is None in create_audit_pipeline; add a test creating two unnamed pipelines back to back.","commit_id":"6031308bd2fc5c7a9c2a6a3876b830712a6c2262"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"7fcfe2660e56498814cf4bbbd9291b1d3e7dc227","unresolved":false,"context_lines":[{"line_number":21,"context_line":"and produces an combined :ref:`Action Plan \u003caction_plan_definition\u003e`. The"},{"line_number":22,"context_line":"pipeline is designed for ONESHOT execution."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Clients using API microversion \u003c 1.8 cannot access Audit Pipeline resources."},{"line_number":25,"context_line":"\"\"\""},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"from http import HTTPStatus"}],"source_content_type":"text/x-python","patch_set":11,"id":"78b9b5f3_51332937","line":24,"updated":"2026-08-19 23:44:13.000000000","message":"The new controller docstring states \u0027Clients using API microversion \u003c 1.8 cannot access Audit Pipeline resources.\u0027 No endpoint in AuditPipelinesController checks api_utils.allow_audit_pipeline(); only the V1 index link is hidden below 1.8 (v1/__init__.py). A client requesting 1.0-1.7 can call every /v1/audit_pipelines operation successfully. Because glossary.rst embeds this module via `.. watcher-term:: watcher.api.controllers.v1.audit_pipeline`, the inaccurate claim is published in user documentation.\n\n**Severity**: SUGGESTION | **Confidence**: 0.85\n\n**Impact**: Operators and client authors reading the glossary or API docs will assume lower-microversion clients receive 404 on /v1/audit_pipelines and may rely on that for version negotiation or access control reasoning; the actual behavior differs, which can cause confusion but no data or security impact.\n\n**Recommendation**:\nEither reword the docstring to match the enforced behavior (e.g. \u0027Audit Pipeline resources are advertised in the API index only at microversion \u003e\u003d 1.8\u0027), or, if strict gating is desired, add an allow_audit_pipeline() guard raising HTTPNotFound in the controller endpoints. Given the webhook precedent, rewording is the smaller consistent fix.","commit_id":"30fb1ddc50cfb864e7ad62b95997a9e4b0d7edee"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"fc83daf4caff3fd88f55cefc4c5f23b626b174b3","unresolved":false,"context_lines":[{"line_number":21,"context_line":"and produces an combined :ref:`Action Plan \u003caction_plan_definition\u003e`. The"},{"line_number":22,"context_line":"pipeline is designed for ONESHOT execution."},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Clients using API microversion \u003c 1.8 cannot access Audit Pipeline resources."},{"line_number":25,"context_line":"\"\"\""},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"from http import HTTPStatus"}],"source_content_type":"text/x-python","patch_set":12,"id":"f85c3f7f_eff40caf","line":24,"updated":"2026-08-21 19:44:18.000000000","message":"The controller docstring, the api-ref \u0027.. versionadded:: 1.8\u0027 marker, and parameters.yaml \u0027min_version: 1.8\u0027 all state that Audit Pipeline resources are 1.8-only, but no handler in AuditPipelinesController checks api_utils.allow_audit_pipeline(). The version check in V1._check_version only validates the 1.0-1.8 range, so a client negotiating 1.0-1.7 can list, create, update, cancel and delete pipelines. Only the discovery link in V1.convert() is version-gated.\n\n**Severity**: WARNING | **Confidence**: 0.85\n\n**Impact**: The per-microversion stability guarantee is violated: clients pinned to 1.0-1.7 see and can mutate the new resources, so documented 1.8-only behavior leaks into older negotiated versions.\n\n**Suggestion**:\nGuard the audit_pipelines subtree (each handler, or centrally in _route) with api_utils.allow_audit_pipeline() and raise exception.NotAcceptable when false, matching data_model.py; add a unit test asserting 406 for pipeline requests without the 1.8 header.","commit_id":"12915584484ccbab32bf63743a23513383cd06b9"}],"watcher/common/policies/audit_pipeline.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"aad0c52589a9819e03da5c382ae55a3917e38f28","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        operations\u003d["},{"line_number":77,"context_line":"            {"},{"line_number":78,"context_line":"                \u0027path\u0027: \u0027/v1/audit_pipelines/{audit_pipeline_uuid}\u0027,"},{"line_number":79,"context_line":"                \u0027method\u0027: \u0027PATCH\u0027,"},{"line_number":80,"context_line":"            }"},{"line_number":81,"context_line":"        ],"},{"line_number":82,"context_line":"    ),"}],"source_content_type":"text/x-python","patch_set":1,"id":"4db4fadb_6fdc43e4","line":79,"updated":"2026-07-15 17:24:07.000000000","message":"The audit_pipeline policy file declares HTTP method \u0027PATCH\u0027 for both \u0027start\u0027 and \u0027cancel\u0027 operations, but the AuditPipelinesController registers these as POST via _custom_actions and the endpoints are accessed via POST.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Operators and API documentation generators that read policy operations metadata will see incorrect HTTP methods, potentially causing confusion about which requests are governed by these policy rules. The correct method is POST (matching _custom_actions and the endpoint URLs /v1/audit_pipelines/{u...\n\n**Suggestion**:\nChange \u0027method\u0027: \u0027PATCH\u0027 to \u0027method\u0027: \u0027POST\u0027 for both the \u0027start\u0027 and \u0027cancel\u0027 operations in the policy file. Also update the path to include the action suffix (e.g., \u0027/v1/audit_pipelines/{audit_pipeline_uuid}/start\u0027).","commit_id":"d91bfc806f23a42a606deaac5bd0d85f378f7ef0"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"dcc33c4df8f9ba0e69c020111d999189c1892f0b","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        operations\u003d["},{"line_number":77,"context_line":"            {"},{"line_number":78,"context_line":"                \u0027path\u0027: \u0027/v1/audit_pipelines/{audit_pipeline_uuid}\u0027,"},{"line_number":79,"context_line":"                \u0027method\u0027: \u0027PATCH\u0027,"},{"line_number":80,"context_line":"            }"},{"line_number":81,"context_line":"        ],"},{"line_number":82,"context_line":"    ),"}],"source_content_type":"text/x-python","patch_set":2,"id":"519d58b4_8a980eb5","line":79,"updated":"2026-08-03 22:39:26.000000000","message":"The oslo-policy DocumentedRuleDefault for audit_pipeline:start and audit_pipeline:cancel list HTTP method \u0027PATCH\u0027, but the controller registers them as POST custom actions. API consumers and policy-doc generators will see incorrect method information.\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Policy documentation generators (e.g., oslo-policy-docs) will publish incorrect HTTP methods for these endpoints, misleading API consumers and automated tooling that validates allowed methods against policy.\n\n**Suggestion**:\nChange \u0027method\u0027: \u0027PATCH\u0027 to \u0027method\u0027: \u0027POST\u0027 in both the start and cancel policy operation entries to match the controller\u0027s custom action definitions.","commit_id":"a8c521110b66efb389c82475714fd01006eb7775"}],"watcher/tests/unit/api/v1/test_audit_pipelines.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"61f8d4fa87a757653d55b4952fe6db562189f97b","unresolved":false,"context_lines":[{"line_number":391,"context_line":"        self.assertEqual(HTTPStatus.CONFLICT, response.status_int)"},{"line_number":392,"context_line":""},{"line_number":393,"context_line":""},{"line_number":394,"context_line":"class TestAuditPipelinePolicyEnforcement(api_base.FunctionalTest):"},{"line_number":395,"context_line":"    def setUp(self):"},{"line_number":396,"context_line":"        super().setUp()"},{"line_number":397,"context_line":"        self.headers \u003d {\u0027OpenStack-API-Version\u0027: \u0027infra-optim 1.8\u0027}"}],"source_content_type":"text/x-python","patch_set":3,"id":"af2f29c9_5543fa50","line":394,"updated":"2026-08-07 20:16:22.000000000","message":"The TestAuditPipelinePolicyEnforcement class tests only 4 of the 7 declared policy rules (get_all, get, detail, delete). The create, update, and cancel policy rules — all admin_api-protected write operations — have no policy enforcement verification tests.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: A regression that accidentally weakens or removes the create, update, or cancel policy check would not be caught by the test suite.\n\n**Recommendation**:\nAdd test_policy_disallow_create (POST), test_policy_disallow_update (PUT), and test_policy_disallow_cancel (POST cancel) methods to TestAuditPipelinePolicyEnforcement, following the same _common_policy_check pattern used by the existing tests.","commit_id":"9e8c708a507f07c91b0dc135186d46714d68d5be"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"32afd6d0407e881668c9244c88683f1a9b75588e","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    def test_empty(self):"},{"line_number":48,"context_line":"        response \u003d self.get_json("},{"line_number":49,"context_line":"            \u0027/audit_pipelines\u0027,"},{"line_number":50,"context_line":"            headers\u003d{\u0027OpenStack-API-Version\u0027: \u0027infra-optim 1.8\u0027},"},{"line_number":51,"context_line":"        )"},{"line_number":52,"context_line":"        self.assertEqual([], response[\u0027audit_pipelines\u0027])"},{"line_number":53,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"cb5f4e7f_a7e8844a","line":50,"updated":"2026-08-12 13:31:37.000000000","message":"The test suite for audit pipelines (test_audit_pipelines.py) always sends the \u0027OpenStack-API-Version: infra-optim 1.8\u0027 header. No test verifies that accessing /audit_pipelines endpoints at microversion \u003c 1.8 returns an appropriate error (e.g., NotAcceptable or NotFound).\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Without a test enforcing microversion gating, any future regression or the current missing-gating issue (CF-001) will go undetected.\n\n**Suggestion**:\nAdd a test that accesses /audit_pipelines without the 1.8 header (or with an older version) and asserts an appropriate HTTP error status (406 NotAcceptable), matching the pattern in test_data_model.py.","commit_id":"b4e18054d4dcac23d2a0aca60d6b345e02261db8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"7c8365cd07712edd99cbddee70cc865562844996","unresolved":false,"context_lines":[{"line_number":401,"context_line":"        self.assertEqual(HTTPStatus.CONFLICT, response.status_int)"},{"line_number":402,"context_line":""},{"line_number":403,"context_line":""},{"line_number":404,"context_line":"class TestAuditPipelinePolicyEnforcement(api_base.FunctionalTest):"},{"line_number":405,"context_line":"    def setUp(self):"},{"line_number":406,"context_line":"        super().setUp()"},{"line_number":407,"context_line":"        self.headers \u003d {\u0027OpenStack-API-Version\u0027: \u0027infra-optim 1.8\u0027}"}],"source_content_type":"text/x-python","patch_set":6,"id":"1e05a3dd_1b5327b2","line":404,"updated":"2026-08-12 23:36:57.000000000","message":"The TestAuditPipelinePolicyEnforcement class tests policy denial for get_all, get_one, detail, and delete. The create, update, and cancel actions each have defined policy rules requiring admin_api, but none are tested for policy denial when a non-admin user attempts them.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: A regression that accidentally removes admin_api enforcement on create, update, or cancel would not be caught by the test suite.\n\n**Recommendation**:\nAdd test_policy_disallow_create, test_policy_disallow_update, and test_policy_disallow_cancel tests following the same _common_policy_check pattern used for the existing tests.","commit_id":"0e41ce5bc3e29b7ee72721cb7f23b13c3cf904c5"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"1a7c8d114a6285e2a37da9b2793ae114a5fff8a3","unresolved":false,"context_lines":[{"line_number":401,"context_line":"        self.assertEqual(HTTPStatus.CONFLICT, response.status_int)"},{"line_number":402,"context_line":""},{"line_number":403,"context_line":""},{"line_number":404,"context_line":"class TestAuditPipelinePolicyEnforcement(api_base.FunctionalTest):"},{"line_number":405,"context_line":"    def setUp(self):"},{"line_number":406,"context_line":"        super().setUp()"},{"line_number":407,"context_line":"        self.headers \u003d {\u0027OpenStack-API-Version\u0027: \u0027infra-optim 1.8\u0027}"}],"source_content_type":"text/x-python","patch_set":6,"id":"163c8a76_8d5531d4","line":404,"in_reply_to":"1e05a3dd_1b5327b2","updated":"2026-08-13 18:26:04.000000000","message":"Ack","commit_id":"0e41ce5bc3e29b7ee72721cb7f23b13c3cf904c5"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"9c3dcf02910f21854033b535310fac15c163371c","unresolved":false,"context_lines":[{"line_number":473,"context_line":"        )"},{"line_number":474,"context_line":"        response \u003d func(*args, **kwargs)"},{"line_number":475,"context_line":"        self.assertEqual(HTTPStatus.FORBIDDEN, response.status_int)"},{"line_number":476,"context_line":"        self.assertTrue("},{"line_number":477,"context_line":"            f\"Policy doesn\u0027t allow {rule} to be performed.\","},{"line_number":478,"context_line":"            jsonutils.loads(response.json[\u0027error_message\u0027])[\u0027faultstring\u0027],"},{"line_number":479,"context_line":"        )"}],"source_content_type":"text/x-python","patch_set":7,"id":"92b4eaec_8ecb1add","line":476,"updated":"2026-08-13 20:21:58.000000000","message":"In _common_policy_check, assertTrue is called with the expected error message string as the first argument and the actual faultstring as the second. Since assertTrue(expr, msg) treats its first argument as a truthiness check and the second as a failure message, the assertion always passes regardl...\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: The policy enforcement tests appear to verify the error message but actually never check it. If the faultstring changes or is wrong, these tests will still pass silently, giving false confidence about policy enforcement behavior.\n\n**Suggestion**:\nReplace assertTrue(expected_string, actual_faultstring) with assertIn(expected_string, actual_faultstring) to correctly verify that the expected policy message is present in the actual faultstring.","commit_id":"7fcc2ada06110676158dcc1533d3a46e1f12becf"}]}
