44
55class Badge {
66
7- constructor ( base , key , date ) {
7+ constructor ( base , key , date , useJsonMetadata = true ) {
88 this . base = base
99 this . key = key
1010 this . _json = null
11+ this . useJsonMetadata = useJsonMetadata
1112 this . operator = 'N/A'
1213 this . date = date . substr ( 0 , 10 )
1314 this . pattern = ''
1415 this . platform = ''
1516 this . version = ''
1617
17- if ( isNewCiBadgeBase ( base ) ) {
18+ if ( this . useJsonMetadata ) {
1819 return
1920 }
2021
@@ -36,7 +37,7 @@ class Badge {
3637 applyJson ( json ) {
3738 this . _json = json
3839
39- if ( ! isNewCiBadgeBase ( this . base ) ) {
40+ if ( ! this . useJsonMetadata ) {
4041 return this
4142 }
4243
@@ -85,6 +86,52 @@ class Badge {
8586// Still present in badge buckets but no longer in the CI matrix (omit from dashboard)
8687var CI_DASHBOARD_EXCLUDED_OCP_VERSIONS = [ '4.19' ]
8788
89+ // patternRepo comes from external badge JSON; only link to known GitHub orgs.
90+ var TRUSTED_PATTERN_REPO_PATH_PREFIXES = [
91+ '/validatedpatterns/' ,
92+ '/validatedpatterns-sandbox/'
93+ ]
94+
95+ // Returns true when repoUrl is an https://github.com URL under a trusted org.
96+ function isTrustedPatternRepo ( repoUrl ) {
97+ if ( repoUrl == null || repoUrl === '' ) {
98+ return false
99+ }
100+ try {
101+ var url = new URL ( String ( repoUrl ) . trim ( ) )
102+ if ( url . protocol !== 'https:' ) {
103+ return false
104+ }
105+ if ( url . username !== '' || url . password !== '' ) {
106+ return false
107+ }
108+ if ( url . hostname . toLowerCase ( ) !== 'github.com' ) {
109+ return false
110+ }
111+ var path = url . pathname . toLowerCase ( )
112+ if ( path . length > 1 && path . charAt ( path . length - 1 ) !== '/' ) {
113+ path += '/'
114+ }
115+ for ( var i = 0 ; i < TRUSTED_PATTERN_REPO_PATH_PREFIXES . length ; i ++ ) {
116+ var prefix = TRUSTED_PATTERN_REPO_PATH_PREFIXES [ i ]
117+ if ( path . indexOf ( prefix ) === 0 && path . length > prefix . length ) {
118+ return true
119+ }
120+ }
121+ return false
122+ } catch ( e ) {
123+ return false
124+ }
125+ }
126+
127+ // Only the old bucket uses filename parsing, new CI badge bucket / external raw badges — hydrate metadata from JSON, not filename.
128+ function usesJsonMetadata ( base ) {
129+ if ( base == null || base === '' || String ( base ) . indexOf ( 'storage.googleapis.com/vp-results' ) !== - 1 ) {
130+ return false
131+ }
132+ return true
133+ }
134+
88135function excludeRetiredOcpVersionsFromDashboard ( badges ) {
89136 if ( ! badges || badges . length === 0 ) {
90137 return badges || [ ]
@@ -157,14 +204,6 @@ var CI_PATTERN_DOC_SLUG = {
157204 vsk : 'virtualization-starter-kit'
158205}
159206
160- // New CI badge bucket (S3 keys under ci-badges/) — distinct from legacy vp-results filenames.
161-
162- var NEW_CI_BADGE_KEY_PREFIX = "https://vp-qe-ci-badges"
163-
164- function isNewCiBadgeBase ( base ) {
165- return base != null && base . startsWith ( NEW_CI_BADGE_KEY_PREFIX )
166- }
167-
168207function normalizeInfraProvider ( provider ) {
169208 if ( provider == null || provider === '' ) {
170209 return null
@@ -318,6 +357,9 @@ function stringForKey(key) {
318357 if ( key == 'nutanix' ) {
319358 return 'Nutanix'
320359 }
360+ if ( key == 'rhoso-gitops' ) {
361+ return 'RHOSO GitOps'
362+ }
321363 return key
322364}
323365
@@ -505,7 +547,7 @@ function renderBadgeHtml(badge, field) {
505547 }
506548
507549 let envLink = encodeURI ( badge_url )
508- let branchLink = json_obj . patternRepo != null ? encodeURI ( json_obj . patternRepo ) : null
550+ let branchLink = isTrustedPatternRepo ( json_obj . patternRepo ) ? encodeURI ( json_obj . patternRepo ) : null
509551 let badgeText = '<span class="ci-label">'
510552 badgeText += '<a href="' + envLink + '"><span class="' + badgeClass + '"><i class="ci-icon fas fa-fw fa-brands fa-git-alt" aria-hidden="true"></i>' + envLabel + '</span></a>'
511553 if ( branchLink != null ) {
@@ -632,7 +674,8 @@ function platformDisplayName(platform) {
632674 'azr' : 'Azure' ,
633675 'gcp' : 'Google Cloud' ,
634676 'nutanix' : 'Nutanix' ,
635- 'intel' : 'On-prem (Intel)'
677+ 'intel' : 'On-prem (Intel)' ,
678+ 'baremetal' : 'Baremetal' ,
636679 }
637680 return names [ platform ] || stringForKey ( platform )
638681}
@@ -843,6 +886,7 @@ function renderDashboardTableRow(badge) {
843886function isProductionSite ( ) {
844887 var host = window . location . hostname
845888 return host === 'validatedpatterns.io' ||
889+ host === 'netlify.app' ||
846890 host === 'localhost' ||
847891 host === '127.0.0.1'
848892}
@@ -1063,7 +1107,7 @@ function renderPatternCard(pattern, platformBadges, comboBadges, tracker) {
10631107 var platformColor = tracker . platforms [ b . platform ] || 'unavailable'
10641108 html += '<span class="ci-card-platform" title="' + platformDisplayName ( b . platform ) + '">'
10651109 html += '<span class="ci-card-platform-dot ' + platformColor + '" id="ci-card-dot-' + patternId + '-' + sanitizeId ( b . platform ) + '"></span>'
1066- html += '<span class="ci-card-platform-label">' + stringForKey ( b . platform ) + '</span>'
1110+ html += '<span class="ci-card-platform-label">' + platformDisplayName ( b . platform ) + '</span>'
10671111 html += '</span>'
10681112 } )
10691113 html += '</div>'
@@ -1283,12 +1327,8 @@ function getBadges(xmlText, bucket_url, badge_set) {
12831327
12841328 for ( let i = 0 ; i < l ; i ++ ) {
12851329 let key = entries [ i ] . childNodes [ 0 ] . nodeValue
1286- if ( badge_set == "GA" && key . endsWith ( "stable-badge.json" ) ) {
1287- badges . push ( new Badge ( bucket_url , key , getBadgeDate ( entries [ i ] ) ) ) ;
1288- } else if ( badge_set == "early" && ( key . endsWith ( "prerelease-badge.json" ) || key . endsWith ( "nightly-badge.json" ) || key . endsWith ( "operator-badge.json" ) ) ) {
1289- badges . push ( new Badge ( bucket_url , key , getBadgeDate ( entries [ i ] ) ) ) ;
1290- } else if ( badge_set == "all" && key . endsWith ( "-badge.json" ) ) {
1291- badges . push ( new Badge ( bucket_url , key , getBadgeDate ( entries [ i ] ) ) ) ;
1330+ if ( badgeKeyMatchesSet ( key , badge_set ) ) {
1331+ badges . push ( new Badge ( bucket_url , key , getBadgeDate ( entries [ i ] ) , usesJsonMetadata ( bucket_url ) ) )
12921332 } else {
12931333 console . log ( "Skipping: " + key ) ;
12941334 }
@@ -1379,6 +1419,36 @@ function getBucketOptions(input) {
13791419 return options
13801420}
13811421
1422+ function badgeKeyMatchesSet ( key , badge_set ) {
1423+ if ( badge_set === 'GA' && key . endsWith ( 'stable-badge.json' ) ) {
1424+ return true
1425+ }
1426+ if ( badge_set === 'early' && ( key . endsWith ( 'prerelease-badge.json' ) || key . endsWith ( 'nightly-badge.json' ) || key . endsWith ( 'operator-badge.json' ) ) ) {
1427+ return true
1428+ }
1429+ if ( badge_set === 'all' && key . endsWith ( '-badge.json' ) ) {
1430+ return true
1431+ }
1432+ return false
1433+ }
1434+
1435+ function createBadgesFromExternalSources ( sources , badge_set ) {
1436+ const badges = [ ]
1437+ const sourceList = sources || [ ]
1438+ sourceList . forEach ( function ( source ) {
1439+ const base = String ( source . base || '' ) . replace ( / \/ $ / , '' )
1440+ const files = source . files || [ ]
1441+ files . forEach ( function ( file ) {
1442+ if ( ! badgeKeyMatchesSet ( file , badge_set ) ) {
1443+ return
1444+ }
1445+ // Date filled from JSON during enrich
1446+ badges . push ( new Badge ( base , file , '1970-01-01T00:00:00Z' ) )
1447+ } )
1448+ } )
1449+ return badges
1450+ }
1451+
13821452function fetchBucketBadges ( bucket , inputs ) {
13831453 return new Promise ( function ( resolve ) {
13841454 var req = new XMLHttpRequest ( )
@@ -1450,6 +1520,11 @@ function obtainBadges(inputs) {
14501520 }
14511521 allBadges . push . apply ( allBadges , badges || [ ] )
14521522 } )
1523+ var ciSources = createBadgesFromExternalSources ( inputs . ci_sources , options . get ( 'sets' ) )
1524+ if ( ciSources . length > 0 ) {
1525+ console . log ( 'Got ' + ciSources . length + ' external badges' )
1526+ allBadges . push . apply ( allBadges , ciSources )
1527+ }
14531528
14541529 console . log ( 'All badges:' , allBadges )
14551530 return enrichBadgesFromJson ( allBadges )
0 commit comments