Skip to content

Commit 03e2f50

Browse files
committed
Warn when Git URL is not an absolute URL
Warn about some Git URLs that the API server will allow, but won't actually work for builds. https://bugzilla.redhat.com/show_bug.cgi?id=1225420
1 parent 9e5a65b commit 03e2f50

File tree

7 files changed

+38
-46
lines changed

7 files changed

+38
-46
lines changed

Diff for: app/scripts/app.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,11 @@ angular
419419
screenLgMin: 1200, // screen-lg
420420
screenXlgMin: 1600 // screen-xlg
421421
})
422-
.constant('SOURCE_URL_PATTERN', /^((ftp|http|https|git|ssh):\/\/(\w+:{0,1}[^\s@]*@)|git@)?([^\s@]+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/ )
422+
// A (very) basic regex to determine if a URL is an absolute URL, enough to
423+
// warn the user the Git URL probably won't work. This should only be used
424+
// as a sanity test and shouldn't block submitting the form. Rely on the API
425+
// server for any additional validation.
426+
.constant('SOURCE_URL_PATTERN', /^[a-z][a-z0-9+.-@]*:(\/\/)?[0-9a-z_-]+/i)
423427
// http://stackoverflow.com/questions/9038625/detect-if-device-is-ios
424428
.constant('IS_IOS', /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
425429
.constant('amTimeAgoConfig', {

Diff for: app/scripts/controllers/edit/deploymentConfig.js

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ angular.module('openshiftConsole')
2020
Navigate,
2121
ProjectsService,
2222
SecretsService,
23-
SOURCE_URL_PATTERN,
2423
keyValueEditorUtils) {
2524
$scope.projectName = $routeParams.project;
2625
$scope.deploymentConfig = null;

Diff for: app/views/create/fromimage.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
'col-lg-12': !advancedOptions}">
7676
<div class="form-group">
7777
<label for="sourceUrl" class="required">Git Repository URL</label>
78-
<div ng-class="{'has-warning': form.sourceUrl.$dirty && !sourceURLPattern.test(buildConfig.sourceUrl), 'has-error': (form.sourceUrl.$error.required && form.sourceUrl.$dirty)}">
78+
<div ng-class="{'has-warning': form.sourceUrl.$touched && !sourceURLPattern.test(buildConfig.sourceUrl), 'has-error': (form.sourceUrl.$error.required && form.sourceUrl.$dirty)}">
7979
<!-- Unfortunately, we can't set type="url" because some valid values don't pass browser validation. -->
8080
<input class="form-control"
8181
id="sourceUrl"
@@ -98,8 +98,8 @@
9898
<div class="has-error" ng-show="form.sourceUrl.$error.required && form.sourceUrl.$dirty">
9999
<span class="help-block">A Git repository URL is required.</span>
100100
</div>
101-
<div>
102-
<span class="text-warning" ng-if="form.sourceUrl.$dirty && !sourceURLPattern.test(buildConfig.sourceUrl)">Git repository should be a URL.</span>
101+
<div class="has-warning" ng-if="buildConfig.sourceUrl && form.sourceUrl.$touched && !sourceURLPattern.test(buildConfig.sourceUrl)">
102+
<span class="help-block">This might not be a valid Git URL. Check that it is the correct URL to a remote Git repository.</span>
103103
</div>
104104
</div>
105105
</div>

Diff for: app/views/edit/build-config.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ <h3>Source Configuration</h3>
4343
aria-describedby="source-url-help"
4444
required>
4545
</div>
46-
<div>
47-
<span class="text-warning" ng-if="form.sourceUrl.$dirty && !sourceURLPattern.test(updatedBuildConfig.spec.source.git.uri)">Git repository should be a URL.</span>
48-
</div>
4946
<div class="help-block" id="source-url-help">
5047
Git URL of the source code to build.
5148
<span ng-if="!view.advancedOptions">If your Git repository is private, view the <a href="" ng-click="view.advancedOptions = true">advanced options</a> to set up authentication.</span>
5249
</div>
50+
<div class="has-warning" ng-if="updatedBuildConfig.spec.source.git.uri && form.sourceUrl.$touched && !sourceURLPattern.test(buildConfig.sourceUrl)">
51+
<span class="help-block">This might not be a valid Git URL. Check that it is the correct URL to a remote Git repository.</span>
52+
</div>
5353
</div>
5454

5555
</div>

Diff for: dist/scripts/scripts.js

+18-18
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ screenSmMin:768,
530530
screenMdMin:992,
531531
screenLgMin:1200,
532532
screenXlgMin:1600
533-
}).constant("SOURCE_URL_PATTERN", /^((ftp|http|https|git|ssh):\/\/(\w+:{0,1}[^\s@]*@)|git@)?([^\s@]+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/).constant("IS_IOS", /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream).constant("amTimeAgoConfig", {
533+
}).constant("SOURCE_URL_PATTERN", /^[a-z][a-z0-9+.-@]*:(\/\/)?[0-9a-z_-]+/i).constant("IS_IOS", /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream).constant("amTimeAgoConfig", {
534534
titleFormat:"LLL"
535535
}).config([ "$httpProvider", "AuthServiceProvider", "RedirectLoginServiceProvider", "AUTH_CFG", "API_CFG", "kubernetesContainerSocketProvider", function(a, b, c, d, e, f) {
536536
a.interceptors.push("AuthInterceptor"), b.LoginService("RedirectLoginService"), b.LogoutService("DeleteTokenLogoutService"), b.UserStore("LocalStorageUserStore"), c.OAuthClientID(d.oauth_client_id), c.OAuthAuthorizeURI(d.oauth_authorize_uri), c.OAuthRedirectURI(URI(d.oauth_redirect_base).segment("oauth").toString()), f.WebSocketFactory = "ContainerWebSocket";
@@ -6943,7 +6943,7 @@ details:a("getErrorDetails")(b)
69436943
e.unwatchAll(i);
69446944
});
69456945
}));
6946-
} ]), angular.module("openshiftConsole").controller("EditDeploymentConfigController", [ "$scope", "$filter", "$location", "$routeParams", "$uibModal", "AlertMessageService", "AuthorizationService", "BreadcrumbsService", "DataService", "Navigate", "ProjectsService", "SecretsService", "SOURCE_URL_PATTERN", "keyValueEditorUtils", function(a, b, c, d, e, f, g, h, i, j, k, l, m, n) {
6946+
} ]), angular.module("openshiftConsole").controller("EditDeploymentConfigController", [ "$scope", "$filter", "$location", "$routeParams", "$uibModal", "AlertMessageService", "AuthorizationService", "BreadcrumbsService", "DataService", "Navigate", "ProjectsService", "SecretsService", "keyValueEditorUtils", function(a, b, c, d, e, f, g, h, i, j, k, l, m) {
69476947
a.projectName = d.project, a.deploymentConfig = null, a.alerts = {}, a.view = {
69486948
advancedStrategyOptions:!1,
69496949
advancedImageOptions:!1
@@ -6956,7 +6956,7 @@ includeProject:!0
69566956
}), a.deploymentConfigStrategyTypes = [ "Recreate", "Rolling", "Custom" ], f.getAlerts().forEach(function(b) {
69576957
a.alerts[b.name] = b.data;
69586958
}), f.clearAlerts();
6959-
var o = [], p = function(a) {
6959+
var n = [], o = function(a) {
69606960
switch (a) {
69616961
case "Recreate":
69626962
return "recreateParams";
@@ -7018,7 +7018,7 @@ a.updatedDeploymentConfig = angular.copy(a.deploymentConfig), a.containerNames =
70187018
pullSecrets:angular.copy(a.deploymentConfig.spec.template.spec.imagePullSecrets) || [ {
70197019
name:""
70207020
} ]
7021-
}, a.volumeNames = _.map(a.deploymentConfig.spec.template.spec.volumes, "name"), a.strategyData = angular.copy(a.deploymentConfig.spec.strategy), a.originalStrategy = a.strategyData.type, a.strategyParamsPropertyName = p(a.strategyData.type), a.triggers.hasConfigTrigger = _.some(a.updatedDeploymentConfig.spec.triggers, {
7021+
}, a.volumeNames = _.map(a.deploymentConfig.spec.template.spec.volumes, "name"), a.strategyData = angular.copy(a.deploymentConfig.spec.strategy), a.originalStrategy = a.strategyData.type, a.strategyParamsPropertyName = o(a.strategyData.type), a.triggers.hasConfigTrigger = _.some(a.updatedDeploymentConfig.spec.triggers, {
70227022
type:"ConfigChange"
70237023
}), "Custom" !== a.strategyData.type || _.has(a.strategyData, "customParams.environment") || (a.strategyData.customParams.environment = []), i.list("secrets", e, function(b) {
70247024
var c = l.groupSecretsByType(b), d = _.mapValues(c, function(a) {
@@ -7027,7 +7027,7 @@ return _.map(a, "metadata.name");
70277027
a.secretsByType = _.each(d, function(a) {
70287028
a.unshift("");
70297029
});
7030-
}), o.push(i.watchObject("deploymentconfigs", d.deploymentconfig, e, function(b, c) {
7030+
}), n.push(i.watchObject("deploymentconfigs", d.deploymentconfig, e, function(b, c) {
70317031
"MODIFIED" === c && (a.alerts["updated/deleted"] = {
70327032
type:"warning",
70337033
message:"This deployment configuration has changed since you started editing it. You'll need to copy any changes you've made and edit again."
@@ -7044,9 +7044,9 @@ details:b("getErrorDetails")(c)
70447044
};
70457045
}) :void j.toErrorPage("You do not have authority to update deployment config " + d.deploymentconfig + ".", "access_denied");
70467046
}));
7047-
var q = function() {
7047+
var p = function() {
70487048
return "Custom" !== a.strategyData.type && "Custom" !== a.originalStrategy && a.strategyData.type !== a.originalStrategy;
7049-
}, r = function(b) {
7049+
}, q = function(b) {
70507050
if (!_.has(a.strategyData, b)) {
70517051
var c = e.open({
70527052
animation:!0,
@@ -7066,21 +7066,21 @@ cancelButtonText:"No"
70667066
}
70677067
});
70687068
c.result.then(function() {
7069-
a.strategyData[b] = angular.copy(a.strategyData[p(a.originalStrategy)]);
7069+
a.strategyData[b] = angular.copy(a.strategyData[o(a.originalStrategy)]);
70707070
}, function() {
70717071
a.strategyData[b] = {};
70727072
});
70737073
}
70747074
};
70757075
a.strategyChanged = function() {
7076-
var b = p(a.strategyData.type);
7077-
q() ? r(b) :_.has(a.strategyData, b) || ("Custom" !== a.strategyData.type ? a.strategyData[b] = {} :a.strategyData[b] = {
7076+
var b = o(a.strategyData.type);
7077+
p() ? q(b) :_.has(a.strategyData, b) || ("Custom" !== a.strategyData.type ? a.strategyData[b] = {} :a.strategyData[b] = {
70787078
image:"",
70797079
command:[],
70807080
environment:[]
70817081
}), a.strategyParamsPropertyName = b;
70827082
};
7083-
var s = function(a, b, c, d) {
7083+
var r = function(a, b, c, d) {
70847084
var e = {
70857085
kind:"ImageStreamTag",
70867086
namespace:b.namespace,
@@ -7094,12 +7094,12 @@ containerNames:[ a ],
70947094
from:e
70957095
}
70967096
}, c;
7097-
}, t = function() {
7097+
}, s = function() {
70987098
var b = _.reject(a.updatedDeploymentConfig.spec.triggers, function(a) {
70997099
return "ImageChange" === a.type || "ConfigChange" === a.type;
71007100
});
71017101
return _.each(a.containerConfigByName, function(c, d) {
7102-
if (c.hasDeploymentTrigger) b.push(s(d, c.triggerData.istag, c.triggerData.data, c.triggerData.automatic)); else {
7102+
if (c.hasDeploymentTrigger) b.push(r(d, c.triggerData.istag, c.triggerData.data, c.triggerData.automatic)); else {
71037103
var e = _.find(a.updatedDeploymentConfig.spec.template.spec.containers, {
71047104
name:d
71057105
});
@@ -7114,10 +7114,10 @@ a.disableInputs = !0, _.each(a.containerConfigByName, function(b, c) {
71147114
var d = _.find(a.updatedDeploymentConfig.spec.template.spec.containers, {
71157115
name:c
71167116
});
7117-
d.env = n.compactEntries(b.env);
7118-
}), q() && delete a.strategyData[p(a.originalStrategy)], "Custom" !== a.strategyData.type ? _.each([ "pre", "mid", "post" ], function(b) {
7119-
_.has(a.strategyData, [ a.strategyParamsPropertyName, b, "execNewPod", "env" ]) && (a.strategyData[a.strategyParamsPropertyName][b].execNewPod.env = n.compactEntries(a.strategyData[a.strategyParamsPropertyName][b].execNewPod.env));
7120-
}) :_.has(a, "strategyData.customParams.environment") && (a.strategyData.customParams.environment = n.compactEntries(a.strategyData.customParams.environment)), a.updatedDeploymentConfig.spec.template.spec.imagePullSecrets = _.filter(a.secrets.pullSecrets, "name"), a.updatedDeploymentConfig.spec.strategy = a.strategyData, a.updatedDeploymentConfig.spec.triggers = t(), i.update("deploymentconfigs", a.updatedDeploymentConfig.metadata.name, a.updatedDeploymentConfig, a.context).then(function() {
7117+
d.env = m.compactEntries(b.env);
7118+
}), p() && delete a.strategyData[o(a.originalStrategy)], "Custom" !== a.strategyData.type ? _.each([ "pre", "mid", "post" ], function(b) {
7119+
_.has(a.strategyData, [ a.strategyParamsPropertyName, b, "execNewPod", "env" ]) && (a.strategyData[a.strategyParamsPropertyName][b].execNewPod.env = m.compactEntries(a.strategyData[a.strategyParamsPropertyName][b].execNewPod.env));
7120+
}) :_.has(a, "strategyData.customParams.environment") && (a.strategyData.customParams.environment = m.compactEntries(a.strategyData.customParams.environment)), a.updatedDeploymentConfig.spec.template.spec.imagePullSecrets = _.filter(a.secrets.pullSecrets, "name"), a.updatedDeploymentConfig.spec.strategy = a.strategyData, a.updatedDeploymentConfig.spec.triggers = s(), i.update("deploymentconfigs", a.updatedDeploymentConfig.metadata.name, a.updatedDeploymentConfig, a.context).then(function() {
71217121
f.addAlert({
71227122
name:a.updatedDeploymentConfig.metadata.name,
71237123
data:{
@@ -7135,7 +7135,7 @@ details:b("getErrorDetails")(c)
71357135
};
71367136
});
71377137
}, a.$on("$destroy", function() {
7138-
i.unwatchAll(o);
7138+
i.unwatchAll(n);
71397139
});
71407140
} ]), angular.module("openshiftConsole").controller("EditAutoscalerController", [ "$scope", "$filter", "$routeParams", "$window", "APIService", "AuthorizationService", "BreadcrumbsService", "DataService", "HPAService", "MetricsService", "Navigate", "ProjectsService", "keyValueEditorUtils", function(a, b, c, d, e, f, g, h, i, j, k, l, m) {
71417141
if (!c.kind || !c.name) return void k.toErrorPage("Kind or name parameter missing.");

Diff for: dist/scripts/templates.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -4656,7 +4656,7 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
46564656
" 'col-lg-12': !advancedOptions}\">\n" +
46574657
"<div class=\"form-group\">\n" +
46584658
"<label for=\"sourceUrl\" class=\"required\">Git Repository URL</label>\n" +
4659-
"<div ng-class=\"{'has-warning': form.sourceUrl.$dirty && !sourceURLPattern.test(buildConfig.sourceUrl), 'has-error': (form.sourceUrl.$error.required && form.sourceUrl.$dirty)}\">\n" +
4659+
"<div ng-class=\"{'has-warning': form.sourceUrl.$touched && !sourceURLPattern.test(buildConfig.sourceUrl), 'has-error': (form.sourceUrl.$error.required && form.sourceUrl.$dirty)}\">\n" +
46604660
"\n" +
46614661
"<input class=\"form-control\" id=\"sourceUrl\" name=\"sourceUrl\" type=\"text\" required aria-describedby=\"from_source_help\" ng-model=\"buildConfig.sourceUrl\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\">\n" +
46624662
"</div>\n" +
@@ -4667,8 +4667,8 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
46674667
"<div class=\"has-error\" ng-show=\"form.sourceUrl.$error.required && form.sourceUrl.$dirty\">\n" +
46684668
"<span class=\"help-block\">A Git repository URL is required.</span>\n" +
46694669
"</div>\n" +
4670-
"<div>\n" +
4671-
"<span class=\"text-warning\" ng-if=\"form.sourceUrl.$dirty && !sourceURLPattern.test(buildConfig.sourceUrl)\">Git repository should be a URL.</span>\n" +
4670+
"<div class=\"has-warning\" ng-if=\"buildConfig.sourceUrl && form.sourceUrl.$touched && !sourceURLPattern.test(buildConfig.sourceUrl)\">\n" +
4671+
"<span class=\"help-block\">This might not be a valid Git URL. Check that it is the correct URL to a remote Git repository.</span>\n" +
46724672
"</div>\n" +
46734673
"</div>\n" +
46744674
"</div>\n" +
@@ -8038,13 +8038,13 @@ angular.module('openshiftConsoleTemplates', []).run(['$templateCache', function(
80388038
"\n" +
80398039
"<input class=\"form-control\" id=\"sourceUrl\" name=\"sourceUrl\" ng-model=\"updatedBuildConfig.spec.source.git.uri\" type=\"text\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" aria-describedby=\"source-url-help\" required>\n" +
80408040
"</div>\n" +
8041-
"<div>\n" +
8042-
"<span class=\"text-warning\" ng-if=\"form.sourceUrl.$dirty && !sourceURLPattern.test(updatedBuildConfig.spec.source.git.uri)\">Git repository should be a URL.</span>\n" +
8043-
"</div>\n" +
80448041
"<div class=\"help-block\" id=\"source-url-help\">\n" +
80458042
"Git URL of the source code to build.\n" +
80468043
"<span ng-if=\"!view.advancedOptions\">If your Git repository is private, view the <a href=\"\" ng-click=\"view.advancedOptions = true\">advanced options</a> to set up authentication.</span>\n" +
80478044
"</div>\n" +
8045+
"<div class=\"has-warning\" ng-if=\"updatedBuildConfig.spec.source.git.uri && form.sourceUrl.$touched && !sourceURLPattern.test(buildConfig.sourceUrl)\">\n" +
8046+
"<span class=\"help-block\">This might not be a valid Git URL. Check that it is the correct URL to a remote Git repository.</span>\n" +
8047+
"</div>\n" +
80488048
"</div>\n" +
80498049
"</div>\n" +
80508050
"<div class=\"col-lg-4\" ng-if=\"view.advancedOptions\">\n" +

Diff for: test/spec/controllers/create/createFromImageSpec.js

+3-14
Original file line numberDiff line numberDiff line change
@@ -69,22 +69,16 @@ describe("CreateFromImageController", function(){
6969
expect(match).not.toBeNull();
7070
});
7171

72-
it("valid http URL, without http part", function(){
72+
it("invalid http URL, without http part", function(){
7373
var match = 'example.com/dir1/dir2'.match($scope.sourceURLPattern);
74-
expect(match).not.toBeNull();
74+
expect(match).toBeNull();
7575
});
7676

77-
7877
it("valid http URL with user and password", function(){
7978
var match = 'http://user:[email protected]/dir1/dir2'.match($scope.sourceURLPattern);
8079
expect(match).not.toBeNull();
8180
});
8281

83-
it("invalid http URL with user and password containing space", function(){
84-
var match = 'http://user:pa [email protected]/dir1/dir2'.match($scope.sourceURLPattern);
85-
expect(match).toBeNull();
86-
});
87-
8882
it("valid http URL with user and password with special characters", function(){
8983
var match = 'https://user:[email protected]/gerrit/p/myrepo.git'.match($scope.sourceURLPattern);
9084
expect(match).not.toBeNull();
@@ -115,11 +109,6 @@ describe("CreateFromImageController", function(){
115109
expect(match).not.toBeNull();
116110
});
117111

118-
it("invalid git+ssh URL (double @@)", function(){
119-
var match = 'git@@example.com:dir1/dir2'.match($scope.sourceURLPattern);
120-
expect(match).toBeNull();
121-
});
122-
123112
it("valid ssh URL", function(){
124113
var match = 'ssh://[email protected]/dir1/dir2'.match($scope.sourceURLPattern);
125114
expect(match).not.toBeNull();
@@ -129,5 +118,5 @@ describe("CreateFromImageController", function(){
129118
var match = 'ssh://[email protected]:8080/dir1/dir2'.match($scope.sourceURLPattern);
130119
expect(match).not.toBeNull();
131120
});
132-
121+
133122
});

0 commit comments

Comments
 (0)