Skip to content

Commit edb1c0e

Browse files
Add intelligent bot user detection for conditional pipeline triggering
- Add gitlab_user_login field to CiContext to capture GITLAB_USER_LOGIN - Add is_bot_user() function to detect project/group access token bots - Update trigger_pipeline() to only manually trigger for bot users - Human users get automatic pipeline triggering, bots get manual triggering - Improves efficiency while maintaining compatibility with group/project tokens Bot patterns detected: - project_{id}_bot{suffix} (project access tokens) - group_{id}_bot_{hash} (group access tokens) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 4cdbd32 commit edb1c0e

File tree

1 file changed

+49
-3
lines changed

1 file changed

+49
-3
lines changed

cicd/test_git_file_changed.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class CiContext:
3030
pipeline_id: Optional[str]
3131
pipeline_source: Optional[str]
3232
commit_sha_short: Optional[str]
33+
gitlab_user_login: Optional[str]
3334

3435
# Source branch is only meaningful when running in an MR pipeline
3536
is_mr: bool
@@ -158,11 +159,14 @@ def build_context(ns: argparse.Namespace) -> CiContext:
158159
api_url=api_url,
159160
server_host=server_host,
160161
project_id=ns.project_id or int(_req_env("CI_PROJECT_ID")),
161-
project_path=os.getenv("CI_PROJECT_PATH", "swiss-armed-forces/cyber-command/cea/loom"),
162+
project_path=os.getenv(
163+
"CI_PROJECT_PATH", "swiss-armed-forces/cyber-command/cea/loom"
164+
),
162165
job_token=os.getenv("CI_JOB_TOKEN"),
163166
pipeline_id=os.getenv("CI_PIPELINE_ID"),
164167
pipeline_source=os.getenv("CI_PIPELINE_SOURCE"),
165168
commit_sha_short=os.getenv("CI_COMMIT_SHORT_SHA"),
169+
gitlab_user_login=os.getenv("GITLAB_USER_LOGIN"),
166170
is_mr=is_mr,
167171
source_branch=source_branch,
168172
project_access_token=ns.project_access_token
@@ -358,6 +362,23 @@ def count_consecutive_ci_commits(
358362
# ----------------------------
359363

360364

365+
def is_bot_user(ctx: CiContext) -> bool:
366+
"""
367+
Detect if pipeline was triggered by a bot user (project/group access token).
368+
369+
Bot users created by access tokens follow these patterns:
370+
- Project tokens: project_{id}_bot{suffix}
371+
- Group tokens: group_{id}_bot_{hash}
372+
373+
Returns True if the user appears to be a bot, False otherwise.
374+
If gitlab_user_login is not available, returns False (assumes human).
375+
"""
376+
user_login = ctx.gitlab_user_login or ""
377+
return (user_login.startswith("project_") and "_bot" in user_login) or (
378+
user_login.startswith("group_") and "_bot" in user_login
379+
)
380+
381+
361382
def wait_for_mr_commit_sync(
362383
project: Project,
363384
mr_iid: str,
@@ -414,14 +435,39 @@ def wait_for_mr_commit_sync(
414435

415436
def trigger_pipeline(ctx: CiContext) -> None:
416437
"""
417-
Trigger a new merge request pipeline using the project access token.
418-
Waits for GitLab to sync the latest commit before triggering.
438+
Conditionally trigger a new merge request pipeline using the project access token.
439+
440+
Manual triggering is only needed for bot users (project/group access tokens) because:
441+
- Bot users with CI_JOB_TOKEN: Do NOT auto-trigger pipelines (by design)
442+
- Human users with CI_JOB_TOKEN: DO auto-trigger pipelines normally
443+
444+
This optimization skips redundant manual triggering for human users while ensuring
445+
bot users (like group_*_bot_* or project_*_bot*) still get their pipelines triggered.
446+
447+
Waits for GitLab to sync the latest commit before triggering to ensure the
448+
pipeline runs on the correct commit, not a stale one.
449+
419450
No-ops in dry-run or if not in MR context or no token provided.
420451
"""
421452
if not ctx.is_mr:
422453
logging.info("Not in MR context; skipping pipeline trigger.")
423454
return
424455

456+
# Check if manual triggering is needed based on user type
457+
is_bot = is_bot_user(ctx)
458+
user_login = ctx.gitlab_user_login or "unknown"
459+
460+
if not is_bot:
461+
logging.info(
462+
"Human user (%s) detected; automatic pipeline triggering expected, skipping manual trigger.",
463+
user_login,
464+
)
465+
return
466+
467+
logging.info(
468+
"Bot user (%s) detected; manual pipeline triggering required.", user_login
469+
)
470+
425471
if not ctx.project_access_token:
426472
logging.info("No project access token provided; skipping pipeline trigger.")
427473
return

0 commit comments

Comments
 (0)