Просмотр исходного кода

Merge pull request #726 from porter-dev/master

Parameterize server URL in GHA -> staging
abelanger5 5 лет назад
Родитель
Сommit
2b38d1977e

+ 61 - 39
dashboard/src/main/auth/Login.tsx

@@ -17,8 +17,10 @@ type StateType = {
   password: string;
   emailError: boolean;
   credentialError: boolean;
+  hasBasic: boolean;
   hasGithub: boolean;
   hasGoogle: boolean;
+  hasResetPassword: boolean;
 };
 
 export default class Login extends Component<PropsType, StateType> {
@@ -27,8 +29,10 @@ export default class Login extends Component<PropsType, StateType> {
     password: "",
     emailError: false,
     credentialError: false,
+    hasBasic: true,
     hasGithub: true,
     hasGoogle: false,
+    hasResetPassword: true,
   };
 
   handleKeyDown = (e: any) => {
@@ -47,8 +51,10 @@ export default class Login extends Component<PropsType, StateType> {
       .getCapabilities("", {}, {})
       .then((res) => {
         this.setState({ 
-          hasGithub: res.data?.github,
-          hasGoogle: res.data?.google,
+          hasBasic: res.data?.basic_login,
+          hasGithub: res.data?.github_login,
+          hasGoogle: res.data?.google_login,
+          hasResetPassword: res.data?.email,
         });
       })
       .catch((err) => console.log(err));
@@ -152,29 +158,12 @@ export default class Login extends Component<PropsType, StateType> {
     }
   };
 
-  render() {
-    let { email, password, credentialError, emailError } = this.state;
+  renderBasicSection = () => {
+    if (this.state.hasBasic) {
+      let { email, password, credentialError, emailError } = this.state;
 
-    return (
-      <StyledLogin>
-        <LoginPanel numOAuth={+this.state.hasGithub + +this.state.hasGoogle}>
-          <OverflowWrapper>
-            <GradientBg />
-          </OverflowWrapper>
-          <FormWrapper>
-            <Logo src={logo} />
-            <Prompt>Log in to Porter</Prompt>
-            {this.renderGithubSection()}
-            {this.renderGoogleSection()}
-            {(this.state.hasGithub || this.state.hasGoogle) ? 
-              <OrWrapper>
-                <Line />
-                <Or>or</Or>
-              </OrWrapper> :
-              null
-            }
-            <DarkMatter />
-            <InputWrapper>
+      return <div>
+        <InputWrapper>
               <Input
                 type="email"
                 placeholder="Email"
@@ -206,23 +195,56 @@ export default class Login extends Component<PropsType, StateType> {
               {this.renderCredentialError()}
             </InputWrapper>
             <Button onClick={this.handleLogin}>Continue</Button>
+      </div>
+    }
+  }
+  
+  renderHelper() {
+    if (this.state.hasResetPassword) {
+      return <Helper>
+        <Link href="/register">Sign up</Link> |
+        <Link href="/password/reset">Forgot password?</Link>
+      </Helper>
+    } 
+
+    return <Helper>
+      <Link href="/register">Sign up</Link>
+    </Helper>
+  }
 
-            <Helper>
-              <Link href="/register">Sign up</Link> |
-              <Link href="/password/reset">Forgot password?</Link>
-            </Helper>
+  render() {
+    return (
+      <StyledLogin>
+        <LoginPanel hasBasic={this.state.hasBasic} numOAuth={+this.state.hasGithub + +this.state.hasGoogle}>
+          <OverflowWrapper>
+            <GradientBg />
+          </OverflowWrapper>
+          <FormWrapper>
+            <Logo src={logo} />
+            <Prompt>Log in to Porter</Prompt>
+            {this.renderGithubSection()}
+            {this.renderGoogleSection()}
+            {(this.state.hasGithub || this.state.hasGoogle) && this.state.hasBasic ? 
+              <OrWrapper>
+                <Line />
+                <Or>or</Or>
+              </OrWrapper> :
+              null
+            }
+            <DarkMatter />
+            {this.renderBasicSection()}
+            {this.renderHelper()}
           </FormWrapper>
         </LoginPanel>
-
         <Footer>
-          © 2021 Porter Technologies Inc. •
-          <Link
-            href="https://docs.getporter.dev/docs/terms-of-service"
-            target="_blank"
-          >
-            Terms & Privacy
-          </Link>
-        </Footer>
+            © 2021 Porter Technologies Inc. •
+            <Link
+              href="https://docs.getporter.dev/docs/terms-of-service"
+              target="_blank"
+            >
+              Terms & Privacy
+            </Link>
+          </Footer>
       </StyledLogin>
     );
   }
@@ -443,8 +465,8 @@ const GradientBg = styled.div`
 
 const LoginPanel = styled.div`
   width: 330px;
-  height: ${(props: { numOAuth: number }) =>
-    430 + props.numOAuth * 50}px;
+  height: ${(props: { numOAuth: number, hasBasic: boolean }) =>
+    280 + +props.hasBasic * 150 + props.numOAuth * 50}px;
   background: white;
   margin-top: -20px;
   border-radius: 10px;

+ 59 - 50
dashboard/src/main/auth/Register.tsx

@@ -20,6 +20,7 @@ type StateType = {
   confirmPasswordError: boolean;
   hasGithub: boolean;
   hasGoogle: boolean;
+  hasBasic: boolean;
 };
 
 export default class Register extends Component<PropsType, StateType> {
@@ -29,6 +30,7 @@ export default class Register extends Component<PropsType, StateType> {
     confirmPassword: "",
     emailError: false,
     confirmPasswordError: false,
+    hasBasic: true,
     hasGithub: true,
     hasGoogle: false,
   };
@@ -45,8 +47,9 @@ export default class Register extends Component<PropsType, StateType> {
       .getCapabilities("", {}, {})
       .then((res) => {
         this.setState({ 
-          hasGithub: res.data?.github,
-          hasGoogle: res.data?.google,
+          hasGithub: res.data?.github_login,
+          hasGoogle: res.data?.google_login,
+          hasBasic: res.data?.basic_login,
         });
       })
       .catch((err) => console.log(err));
@@ -133,7 +136,7 @@ export default class Register extends Component<PropsType, StateType> {
           <OAuthButton onClick={this.githubRedirect}>
             <IconWrapper>
               <Icon src={github} />
-              Log in with GitHub
+              Sign up with GitHub
             </IconWrapper>
           </OAuthButton>
       );
@@ -146,14 +149,14 @@ export default class Register extends Component<PropsType, StateType> {
           <OAuthButton onClick={this.googleRedirect}>
             <IconWrapper>
               <StyledGoogleIcon />
-              Log in with Google
+              Sign up with Google
             </IconWrapper>
           </OAuthButton>
       );
     }
   };
 
-  render() {
+  renderBasicSection = () => {
     let {
       email,
       password,
@@ -162,9 +165,55 @@ export default class Register extends Component<PropsType, StateType> {
       confirmPasswordError,
     } = this.state;
 
+    if (this.state.hasBasic) {
+      return <div><InputWrapper>
+        <Input
+          type="email"
+          placeholder="Email"
+          value={email}
+          onChange={(e: ChangeEvent<HTMLInputElement>) =>
+            this.setState({ email: e.target.value, emailError: false })
+          }
+          valid={!emailError}
+        />
+        {this.renderEmailError()}
+      </InputWrapper>
+      <Input
+        type="password"
+        placeholder="Password"
+        value={password}
+        onChange={(e: ChangeEvent<HTMLInputElement>) =>
+          this.setState({
+            password: e.target.value,
+            confirmPasswordError: false,
+          })
+        }
+        valid={true}
+      />
+      <InputWrapper>
+        <Input
+          type="password"
+          placeholder="Confirm Password"
+          value={confirmPassword}
+          onChange={(e: ChangeEvent<HTMLInputElement>) =>
+            this.setState({
+              confirmPassword: e.target.value,
+              confirmPasswordError: false,
+            })
+          }
+          valid={!confirmPasswordError}
+        />
+        {this.renderConfirmPasswordError()}
+      </InputWrapper>
+      <Button onClick={this.handleRegister}>Continue</Button>
+      </div>
+    }
+  }
+
+  render() {
     return (
       <StyledRegister>
-        <LoginPanel numOAuth={+this.state.hasGithub + +this.state.hasGoogle}>
+        <LoginPanel hasBasic={this.state.hasBasic} numOAuth={+this.state.hasGithub + +this.state.hasGoogle}>
           <OverflowWrapper>
             <GradientBg />
           </OverflowWrapper>
@@ -173,7 +222,7 @@ export default class Register extends Component<PropsType, StateType> {
             <Prompt>Sign up for Porter</Prompt>
             {this.renderGithubSection()}
             {this.renderGoogleSection()}
-            {(this.state.hasGithub || this.state.hasGoogle) ? 
+            {(this.state.hasGithub || this.state.hasGoogle) && this.state.hasBasic ? 
               <OrWrapper>
                 <Line />
                 <Or>or</Or>
@@ -181,47 +230,7 @@ export default class Register extends Component<PropsType, StateType> {
               null
             }
             <DarkMatter />
-            <InputWrapper>
-              <Input
-                type="email"
-                placeholder="Email"
-                value={email}
-                onChange={(e: ChangeEvent<HTMLInputElement>) =>
-                  this.setState({ email: e.target.value, emailError: false })
-                }
-                valid={!emailError}
-              />
-              {this.renderEmailError()}
-            </InputWrapper>
-            <Input
-              type="password"
-              placeholder="Password"
-              value={password}
-              onChange={(e: ChangeEvent<HTMLInputElement>) =>
-                this.setState({
-                  password: e.target.value,
-                  confirmPasswordError: false,
-                })
-              }
-              valid={true}
-            />
-            <InputWrapper>
-              <Input
-                type="password"
-                placeholder="Confirm Password"
-                value={confirmPassword}
-                onChange={(e: ChangeEvent<HTMLInputElement>) =>
-                  this.setState({
-                    confirmPassword: e.target.value,
-                    confirmPasswordError: false,
-                  })
-                }
-                valid={!confirmPasswordError}
-              />
-              {this.renderConfirmPasswordError()}
-            </InputWrapper>
-            <Button onClick={this.handleRegister}>Continue</Button>
-
+            {this.renderBasicSection()}
             <Helper>
               Have an account?
               <Link href="/login">Sign in</Link>
@@ -456,8 +465,8 @@ const GradientBg = styled.div`
 
 const LoginPanel = styled.div`
   width: 330px;
-  height: ${(props: { numOAuth: number }) =>
-    450 + props.numOAuth * 50}px;
+  height: ${(props: { numOAuth: number, hasBasic: boolean }) =>
+    270 + +props.hasBasic * 180 + props.numOAuth * 50}px;
   background: white;
   margin-top: -20px;
   border-radius: 10px;

+ 26 - 4
internal/adapter/gorm.go

@@ -21,15 +21,35 @@ func New(conf *config.DBConf) (*gorm.DB, error) {
 		})
 	}
 
-	dsn := fmt.Sprintf(
-		"user=%s password=%s port=%d host=%s sslmode=disable",
+	// connect to default postgres instance first
+	baseDSN := fmt.Sprintf(
+		"user=%s password=%s port=%d host=%s",
 		conf.Username,
 		conf.Password,
 		conf.Port,
 		conf.Host,
 	)
 
-	res, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
+	if conf.ForceSSL {
+		baseDSN = baseDSN + " sslmode=require"
+	} else {
+		baseDSN = baseDSN + " sslmode=disable"
+	}
+
+	postgresDSN := baseDSN + " database=postgres"
+	targetDSN := baseDSN + " database=" + conf.DbName
+
+	defaultDB, err := gorm.Open(postgres.Open(postgresDSN), &gorm.Config{
+		FullSaveAssociations: true,
+	})
+
+	// attempt to create the database
+	if conf.DbName != "" {
+		defaultDB.Exec(fmt.Sprintf("CREATE DATABASE %s;", conf.DbName))
+	}
+
+	// open the database connection
+	res, err := gorm.Open(postgres.Open(targetDSN), &gorm.Config{
 		FullSaveAssociations: true,
 	})
 
@@ -40,7 +60,9 @@ func New(conf *config.DBConf) (*gorm.DB, error) {
 	if err != nil {
 		for {
 			time.Sleep(timeout)
-			res, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
+			res, err = gorm.Open(postgres.Open(targetDSN), &gorm.Config{
+				FullSaveAssociations: true,
+			})
 
 			if retryCount > 3 {
 				return nil, err

+ 4 - 0
internal/config/config.go

@@ -35,8 +35,11 @@ type ServerConf struct {
 	DefaultApplicationHelmRepoURL string `env:"HELM_APP_REPO_URL,default=https://charts.dev.getporter.dev"`
 	DefaultAddonHelmRepoURL       string `env:"HELM_ADD_ON_REPO_URL,default=https://chart-addons.dev.getporter.dev"`
 
+	BasicLoginEnabled bool `env:"BASIC_LOGIN_ENABLED,default=true"`
+
 	GithubClientID     string `env:"GITHUB_CLIENT_ID"`
 	GithubClientSecret string `env:"GITHUB_CLIENT_SECRET"`
+	GithubLoginEnabled bool   `env:"GITHUB_LOGIN_ENABLED,default=true"`
 
 	GoogleClientID         string `env:"GOOGLE_CLIENT_ID"`
 	GoogleClientSecret     string `env:"GOOGLE_CLIENT_SECRET"`
@@ -66,6 +69,7 @@ type DBConf struct {
 	Username string `env:"DB_USER,default=porter"`
 	Password string `env:"DB_PASS,default=porter"`
 	DbName   string `env:"DB_NAME,default=porter"`
+	ForceSSL bool   `env:"DB_FORCE_SSL,default=false"`
 
 	SQLLite     bool   `env:"SQL_LITE,default=false"`
 	SQLLitePath string `env:"SQL_LITE_PATH,default=/porter/porter.db"`

+ 4 - 2
internal/integrations/ci/actions/actions.go

@@ -17,6 +17,8 @@ import (
 )
 
 type GithubActions struct {
+	ServerURL string
+
 	GitIntegration *models.GitRepo
 	GitRepoName    string
 	GitRepoOwner   string
@@ -157,7 +159,7 @@ func (g *GithubActions) GetGithubActionYAML() ([]byte, error) {
 	gaSteps := []GithubActionYAMLStep{
 		getCheckoutCodeStep(),
 		getDownloadPorterStep(),
-		getConfigurePorterStep(g.getPorterTokenSecretName()),
+		getConfigurePorterStep(g.ServerURL, g.getPorterTokenSecretName()),
 	}
 
 	if g.DockerFilePath == "" {
@@ -166,7 +168,7 @@ func (g *GithubActions) GetGithubActionYAML() ([]byte, error) {
 		gaSteps = append(gaSteps, getDockerBuildPushStep(g.getBuildEnvSecretName(), g.DockerFilePath, g.ImageRepoURL))
 	}
 
-	gaSteps = append(gaSteps, deployPorterWebhookStep(g.getWebhookSecretName(), g.ImageRepoURL))
+	gaSteps = append(gaSteps, deployPorterWebhookStep(g.ServerURL, g.getWebhookSecretName()))
 
 	branch := g.GitBranch
 

+ 6 - 5
internal/integrations/ci/actions/steps.go

@@ -31,15 +31,16 @@ func getDownloadPorterStep() GithubActionYAMLStep {
 }
 
 const configure string = `
+sudo porter config set-host %s
 sudo porter auth login --token ${{secrets.%s}}
 sudo porter docker configure
 `
 
-func getConfigurePorterStep(porterTokenSecretName string) GithubActionYAMLStep {
+func getConfigurePorterStep(serverURL, porterTokenSecretName string) GithubActionYAMLStep {
 	return GithubActionYAMLStep{
 		Name: "Configure Porter",
 		ID:   "configure_porter",
-		Run:  fmt.Sprintf(configure, porterTokenSecretName),
+		Run:  fmt.Sprintf(configure, serverURL, porterTokenSecretName),
 	}
 }
 
@@ -77,13 +78,13 @@ func getBuildPackPushStep(envSecretName, folderPath, repoURL string) GithubActio
 }
 
 const deployPorter string = `
-curl -X POST "https://dashboard.getporter.dev/api/webhooks/deploy/${{secrets.%s}}?commit=$(git rev-parse --short HEAD)&repository=%s"
+curl -X POST "%s/api/webhooks/deploy/${{secrets.%s}}?commit=$(git rev-parse --short HEAD)"
 `
 
-func deployPorterWebhookStep(webhookTokenSecretName, repoURL string) GithubActionYAMLStep {
+func deployPorterWebhookStep(serverURL, webhookTokenSecretName string) GithubActionYAMLStep {
 	return GithubActionYAMLStep{
 		Name: "Deploy on Porter",
 		ID:   "deploy_porter",
-		Run:  fmt.Sprintf(deployPorter, webhookTokenSecretName, repoURL),
+		Run:  fmt.Sprintf(deployPorter, serverURL, webhookTokenSecretName),
 	}
 }

+ 6 - 2
server/api/api.go

@@ -93,9 +93,10 @@ type App struct {
 
 type AppCapabilities struct {
 	Provisioning bool `json:"provisioner"`
-	Subdomains   bool `json:"subdomains"`
 	Github       bool `json:"github"`
-	GoogleLogin  bool `json:"google"`
+	BasicLogin   bool `json:"basic_login"`
+	GithubLogin  bool `json:"github_login"`
+	GoogleLogin  bool `json:"google_login"`
 	Email        bool `json:"email"`
 	Analytics    bool `json:"analytics"`
 }
@@ -172,6 +173,8 @@ func New(conf *AppConfig) (*App, error) {
 			Scopes:       []string{"repo", "read:user", "workflow"},
 			BaseURL:      sc.ServerURL,
 		})
+
+		app.Capabilities.GithubLogin = sc.GithubLoginEnabled
 	}
 
 	if sc.GoogleClientID != "" && sc.GoogleClientSecret != "" {
@@ -200,6 +203,7 @@ func New(conf *AppConfig) (*App, error) {
 
 	app.Capabilities.Email = sc.SendgridAPIKey != ""
 	app.Capabilities.Analytics = sc.SegmentClientKey != ""
+	app.Capabilities.BasicLogin = sc.BasicLoginEnabled
 
 	app.tokenConf = &token.TokenGeneratorConf{
 		TokenSecret: conf.ServerConf.TokenGeneratorSecret,

+ 1 - 0
server/api/deploy_handler.go

@@ -251,6 +251,7 @@ func (app *App) HandleUninstallTemplate(w http.ResponseWriter, r *http.Request)
 				}
 
 				gaRunner := &actions.GithubActions{
+					ServerURL:      app.ServerConf.ServerURL,
 					GitIntegration: gr,
 					GitRepoName:    repoSplit[1],
 					GitRepoOwner:   repoSplit[0],

+ 1 - 0
server/api/git_action_handler.go

@@ -153,6 +153,7 @@ func (app *App) createGitActionFromForm(
 
 	// create the commit in the git repo
 	gaRunner := &actions.GithubActions{
+		ServerURL:      app.ServerConf.ServerURL,
 		GitIntegration: gr,
 		GitRepoName:    repoSplit[1],
 		GitRepoOwner:   repoSplit[0],

+ 2 - 0
server/api/release_handler.go

@@ -791,6 +791,7 @@ func (app *App) HandleUpgradeRelease(w http.ResponseWriter, r *http.Request) {
 				repoSplit := strings.Split(gitAction.GitRepo, "/")
 
 				gaRunner := &actions.GithubActions{
+					ServerURL:      app.ServerConf.ServerURL,
 					GitIntegration: gr,
 					GitRepoName:    repoSplit[1],
 					GitRepoOwner:   repoSplit[0],
@@ -1056,6 +1057,7 @@ func (app *App) HandleRollbackRelease(w http.ResponseWriter, r *http.Request) {
 				}
 
 				gaRunner := &actions.GithubActions{
+					ServerURL:      app.ServerConf.ServerURL,
 					GitIntegration: gr,
 					GitRepoName:    repoSplit[1],
 					GitRepoOwner:   repoSplit[0],

+ 14 - 11
server/router/router.go

@@ -55,11 +55,20 @@ func New(a *api.App) *chi.Mux {
 				),
 			)
 
-			r.Method(
-				"POST",
-				"/users",
-				requestlog.NewHandler(a.HandleCreateUser, l),
-			)
+			// only allow basic create user or basic login if BasicLogin feature is set
+			if a.Capabilities.BasicLogin {
+				r.Method(
+					"POST",
+					"/users",
+					requestlog.NewHandler(a.HandleCreateUser, l),
+				)
+
+				r.Method(
+					"POST",
+					"/login",
+					requestlog.NewHandler(a.HandleLoginUser, l),
+				)
+			}
 
 			r.Method(
 				"DELETE",
@@ -84,12 +93,6 @@ func New(a *api.App) *chi.Mux {
 				requestlog.NewHandler(a.HandleCLILoginExchangeToken, l),
 			)
 
-			r.Method(
-				"POST",
-				"/login",
-				requestlog.NewHandler(a.HandleLoginUser, l),
-			)
-
 			r.Method(
 				"GET",
 				"/auth/check",