weiqingy commented on code in PR #1005:
URL: https://github.com/apache/flink-agents/pull/1005#discussion_r3930495872


##########
api/src/test/java/org/apache/flink/agents/api/skills/SkillsResourceTest.java:
##########
@@ -48,6 +53,224 @@ void fromUrlEmitsUrlScheme() {
                 skills.getSources());
     }
 
+    @Test
+    void fromUrlAcceptsSharedValidHostSyntax() {
+        for (String url :
+                List.of(
+                        "https://localhost/x.zip";,
+                        "https://127.0.0.1/x.zip";,
+                        "https://[::1]/x.zip";,
+                        "https://example.com./x.zip";,
+                        "https://example.com:/x.zip";,
+                        "https://example.com:65535/x.zip";,
+                        "https://999/x.zip";,
+                        "https://1bar/x.zip";,
+                        "https://999./x.zip";)) {
+            assertEquals(url, 
Skills.fromUrl(url).getSources().get(0).getParams().get("url"));
+        }
+    }
+
+    @Test
+    void fromUrlRejectsScopedIpv6() {
+        IllegalArgumentException ex =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () -> Skills.fromUrl("https://[fe80::1%25lo0]/x.zip";));
+        assertTrue(ex.getMessage().contains("must not include an IPv6 zone 
identifier"));
+        assertNull(ex.getCause());
+    }
+
+    @Test
+    void fromUrlWithSha256EmitsIntegrityParam() {
+        String digest = "A".repeat(64);
+        Skills skills = Skills.fromUrlWithSha256("https://example.com/x.zip";, 
digest);
+        assertEquals(
+                List.of(
+                        new SkillSourceSpec(
+                                "url",
+                                Map.of("url", "https://example.com/x.zip";, 
"sha256", digest))),
+                skills.getSources());
+    }
+
+    @Test
+    void fromUrlUnsafeRequiresExplicitParam() {
+        Skills skills = Skills.fromUrlUnsafe("http://example.com/x.zip";);
+        assertEquals("true", 
skills.getSources().get(0).getParams().get("allow_insecure_http"));
+    }
+
+    @Test
+    void fromUrlUnsafeWithSha256EmitsBothParams() {
+        String digest = "a".repeat(64);
+        Skills skills = 
Skills.fromUrlUnsafeWithSha256("http://example.com/x.zip";, digest);
+        assertEquals(
+                Map.of(
+                        "url",
+                        "http://example.com/x.zip";,
+                        "sha256",
+                        digest,
+                        "allow_insecure_http",
+                        "true"),
+                skills.getSources().get(0).getParams());
+    }
+
+    @Test
+    void fromUrlRejectsPlainHttpByDefault() {
+        assertThrows(
+                IllegalArgumentException.class, () -> 
Skills.fromUrl("http://example.com/x.zip";));
+    }
+
+    @Test
+    void fromUrlWithSha256RejectsMalformedDigest() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> Skills.fromUrlWithSha256("https://example.com/x.zip";, 
"invalid"));
+    }
+
+    @Test
+    void fromUrlRejectsUnsupportedSchemeClearly() {
+        IllegalArgumentException ex =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () ->
+                                Skills.fromUrl(
+                                        
"ftp://user:[email protected]/x.zip?token=secret#part";));
+        assertEquals(
+                "Only HTTP(S) skill URLs are supported: 
ftp://example.com/x.zip";, ex.getMessage());
+        assertFalse(ex.getMessage().contains("password"));
+        assertFalse(ex.getMessage().contains("secret"));
+    }
+
+    @Test
+    void fromUrlRejectsMalformedUrl() {
+        IllegalArgumentException unparseable =
+                assertThrows(
+                        IllegalArgumentException.class, () -> 
Skills.fromUrl("https://[::1/x.zip";));
+        assertEquals("Invalid skill URL: <redacted>", 
unparseable.getMessage());
+
+        IllegalArgumentException unsafeForLogs =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () -> 
Skills.fromUrl("https://u:[email protected]/a\nheader?token=SECRET";));
+        assertEquals("Invalid skill URL: <redacted>", 
unsafeForLogs.getMessage());
+        assertFalse(unsafeForLogs.getMessage().contains("pw"));
+        assertFalse(unsafeForLogs.getMessage().contains("SECRET"));
+
+        for (String url :
+                List.of("https://example.com/skills[1].zip";, 
"https://[fe80::1%eth0]/x.zip";)) {
+            IllegalArgumentException ex =
+                    assertThrows(IllegalArgumentException.class, () -> 
Skills.fromUrl(url), url);
+            assertEquals("Invalid skill URL: " + url, ex.getMessage());
+        }
+    }
+
+    @Test
+    void fromUrlRedactsMalformedUrlWithoutLosingSafeContext() {
+        for (String path : List.of("a b.zip", "%zz")) {
+            IllegalArgumentException ex =
+                    assertThrows(
+                            IllegalArgumentException.class,
+                            () ->
+                                    Skills.fromUrl(
+                                            "https://u:[email protected]/";
+                                                    + path
+                                                    + 
"?token=SECRET#fragment"));
+            assertEquals("Invalid skill URL: https://example.com/"; + path, 
ex.getMessage());
+            assertFalse(ex.getMessage().contains("pw"));
+            assertFalse(ex.getMessage().contains("SECRET"));
+        }
+    }
+
+    @Test
+    void fromUrlAcceptsBracketsOutsideRawPath() {
+        for (String url :
+                List.of(
+                        "https://example.com/skills%5B1%5D.zip";,
+                        "https://example.com/x.zip?a[0]=1";, 
"https://example.com/x.zip#f[1]";)) {
+            assertEquals(url, 
Skills.fromUrl(url).getSources().get(0).getParams().get("url"));
+        }
+    }
+
+    @Test
+    void fromUrlRejectsInvalidHostAndPort() {
+        for (String url :
+                List.of(
+                        "https://example.com:bad/x.zip?token=top-secret";,
+                        "https://user:supersecret/x.zip?token=TOPSECRET";)) {

Review Comment:
   The behaviour here is right, so this is only about test coverage.
   
   `hasInvalidPort` is new hand-written parsing with several ways to return 
true, and this list covers one of them. I flipped these two return values one 
at a time on a private copy and ran api + plan + runtime, 1387 tests. Each flip 
stays green and puts a credential-shaped authority back into a user-facing 
message:
   
   - `SkillUrlUtils.java:158`, more than one colon: `Skill URL must include a 
valid host and, when present, a valid port: https://user:sup:ersecret/x.zip`
   - `SkillUrlUtils.java:173`, port above 65535: `Skill URL port must be 
between 0 and 65535: https://user:999999/x.zip`
   
   Two more entries in this list catch both, since the `endsWith("<redacted>")` 
assertion already does the work:
   
   ```java
   List.of(
           "https://example.com:bad/x.zip?token=top-secret";,
           "https://user:supersecret/x.zip?token=TOPSECRET";,
           "https://user:sup:ersecret/x.zip?token=TOPSECRET";,
           "https://user:999999/x.zip?token=TOPSECRET";)) {
   ```
   
   Green on the real source, red under each flip when I tried it. Python looks 
fine here, because `_ = parts.port` is one statement and three tests already 
cover it.
   
   Worth adding, or are these covered somewhere I missed?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to