This is an automated email from the ASF dual-hosted git repository.

dspavlov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git


The following commit(s) were added to refs/heads/master by this push:
     new 5a8889d7 IGNITE-28729: Treat 403 as permanent failure (#237)
5a8889d7 is described below

commit 5a8889d7ccdca75c97eeb09e4512275ea65c5bbc
Author: ignitetcbot <[email protected]>
AuthorDate: Thu May 28 11:25:58 2026 +0300

    IGNITE-28729: Treat 403 as permanent failure (#237)
    
    Codex co-authored-by: Dmitriy Pavlov <[email protected]>
---
 .../IgnitedTcInMemoryIntegrationTest.java          | 42 ++++++++++++++++++++++
 .../tcignited/build/ProactiveFatBuildSync.java     | 20 ++++++++++-
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git 
a/ignite-tc-helper-web/src/test/java/org/apache/ignite/tcignited/IgnitedTcInMemoryIntegrationTest.java
 
b/ignite-tc-helper-web/src/test/java/org/apache/ignite/tcignited/IgnitedTcInMemoryIntegrationTest.java
index 46cba821..8a90f646 100644
--- 
a/ignite-tc-helper-web/src/test/java/org/apache/ignite/tcignited/IgnitedTcInMemoryIntegrationTest.java
+++ 
b/ignite-tc-helper-web/src/test/java/org/apache/ignite/tcignited/IgnitedTcInMemoryIntegrationTest.java
@@ -735,6 +735,48 @@ public class IgnitedTcInMemoryIntegrationTest {
         assertTrue(checkNotNull(running4).isEmpty());
     }
 
+    @Test
+    public void testForbiddenBuildAccessCreatesPermanentFakeBuild() {
+        TeamcityIgnitedModule module = new TeamcityIgnitedModule();
+        module.overrideHttp((basicAuthTok, url) -> {
+            throw new IllegalStateException("Service " + url + " returned 
Invalid Response Code : 403:\n" +
+                "HTTP 403 | Host: ci2.ignite.apache.org | " + url + "\n" +
+                "Not enough permissions to access build");
+        });
+        Injector injector = Guice.createInjector(module, new 
IgniteAndSchedulerTestModule());
+
+        IStringCompactor c = injector.getInstance(IStringCompactor.class);
+        BuildRefDao buildRefDao = 
injector.getInstance(BuildRefDao.class).init();
+        FatBuildDao fatBuildDao = 
injector.getInstance(FatBuildDao.class).init();
+
+        int buildId = 1000044;
+        BuildRef ref = new BuildRef();
+        ref.buildTypeId = "Testbuild";
+        ref.branchName = ITeamcity.REFS_HEADS_MASTER;
+        ref.state = BuildRef.STATE_FINISHED;
+        ref.status = BuildRef.STATUS_SUCCESS;
+        ref.setId(buildId);
+
+        String srvCode = APACHE;
+        int srvIdInt = ITeamcityIgnited.serverIdToInt(srvCode);
+        final TeamcityServiceConnection srvConn = 
injector.getInstance(TeamcityServiceConnection.class);
+        srvConn.init(srvCode);
+
+        buildRefDao.saveChunk(srvIdInt, Lists.newArrayList(ref));
+
+        assertTrue(fatBuildDao.getMissingBuilds(srvIdInt, new int[] 
{buildId}).contains(buildId));
+
+        ProactiveFatBuildSync buildSync = 
injector.getInstance(ProactiveFatBuildSync.class);
+        buildSync.ensureActualizationRequested(srvCode, srvConn);
+
+        FatBuildCompacted fatBuild = fatBuildDao.getFatBuild(srvIdInt, 
buildId);
+
+        assertNotNull(fatBuild);
+        assertTrue(fatBuild.isFakeStub());
+        assertTrue(fatBuild.isCancelled(c));
+        assertTrue(fatBuildDao.getMissingBuilds(srvIdInt, new int[] 
{buildId}).isEmpty());
+    }
+
     public void putOldFashionFakeBuild(IStringCompactor c, FatBuildDao 
fatBuildDao, int buildId, int srvIdInt) {
         FatBuildCompacted fb = fatBuildDao.getFatBuild(srvIdInt, buildId);
 
diff --git 
a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/ProactiveFatBuildSync.java
 
b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/ProactiveFatBuildSync.java
index 8eb33d6b..a024ba37 100644
--- 
a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/ProactiveFatBuildSync.java
+++ 
b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/build/ProactiveFatBuildSync.java
@@ -419,7 +419,8 @@ public class ProactiveFatBuildSync {
         catch (Exception e) {
             Throwable cause = Throwables.getRootCause(e);
 
-            if (cause instanceof FileNotFoundException || cause instanceof 
ServiceConflictException) {
+            if (cause instanceof FileNotFoundException || cause instanceof 
ServiceConflictException ||
+                isPermanentBuildAccessDenied(e)) {
                 logger.info("Loading build [" + buildId + "] for server [" + 
srvName + "] failed:" + e.getMessage(), e);
 
                 if (existingBuild != null) {
@@ -456,6 +457,23 @@ public class ProactiveFatBuildSync {
         return fatBuildDao.saveBuild(srvIdMask, buildId, build, tests, 
problems, statistics, changesList, existingBuild);
     }
 
+    private boolean isPermanentBuildAccessDenied(Throwable e) {
+        for (Throwable cur = e; cur != null; cur = cur.getCause()) {
+            String msg = cur.getMessage();
+
+            if (msg == null)
+                continue;
+
+            String msgLower = msg.toLowerCase();
+
+            if (msgLower.contains("403") && msgLower.contains("not enough 
permissions") &&
+                msgLower.contains("access build"))
+                return true;
+        }
+
+        return false;
+    }
+
     @Nullable
     public FatBuildCompacted transformV5Build(int srvIdMask, int buildId, 
@Nonnull FatBuildCompacted existingBuild) {
         if (Objects.equals(buildId, existingBuild.id())) {

Reply via email to