Merge pull request #6106 from egmar/ghe-auth-support

Support for Github Enteprise for authentication

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot] 2021-02-02 15:59:22 +00:00 committed by GitHub
commit 7a8d9394be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2465 additions and 28 deletions

View File

@ -393,3 +393,43 @@ def test_saml_x509cert_validation(patch, get, admin, headers):
}
})
assert resp.status_code == 200
@pytest.mark.django_db
def test_github_settings(get, put, patch, delete, admin):
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'github'})
get(url, user=admin, expect=200)
delete(url, user=admin, expect=204)
response = get(url, user=admin, expect=200)
data = dict(response.data.items())
put(url, user=admin, data=data, expect=200)
patch(url, user=admin, data={'SOCIAL_AUTH_GITHUB_KEY': '???'}, expect=200)
response = get(url, user=admin, expect=200)
assert response.data['SOCIAL_AUTH_GITHUB_KEY'] == '???'
data.pop('SOCIAL_AUTH_GITHUB_KEY')
put(url, user=admin, data=data, expect=200)
response = get(url, user=admin, expect=200)
assert response.data['SOCIAL_AUTH_GITHUB_KEY'] == ''
@pytest.mark.django_db
def test_github_enterprise_settings(get, put, patch, delete, admin):
url = reverse('api:setting_singleton_detail', kwargs={'category_slug': 'github-enterprise'})
get(url, user=admin, expect=200)
delete(url, user=admin, expect=204)
response = get(url, user=admin, expect=200)
data = dict(response.data.items())
put(url, user=admin, data=data, expect=200)
patch(url, user=admin, data={
'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL': 'example.com',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL': 'example.com',
}, expect=200)
response = get(url, user=admin, expect=200)
assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_URL'] == 'example.com'
assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL'] == 'example.com'
data.pop('SOCIAL_AUTH_GITHUB_ENTERPRISE_URL')
data.pop('SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL')
put(url, user=admin, data=data, expect=200)
response = get(url, user=admin, expect=200)
assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_URL'] == ''
assert response.data['SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL'] == ''

View File

@ -344,6 +344,9 @@ AUTHENTICATION_BACKENDS = (
'social_core.backends.github.GithubOAuth2',
'social_core.backends.github.GithubOrganizationOAuth2',
'social_core.backends.github.GithubTeamOAuth2',
'social_core.backends.github_enterprise.GithubEnterpriseOAuth2',
'social_core.backends.github_enterprise.GithubEnterpriseOrganizationOAuth2',
'social_core.backends.github_enterprise.GithubEnterpriseTeamOAuth2',
'social_core.backends.azuread.AzureADOAuth2',
'awx.sso.backends.SAMLAuth',
'django.contrib.auth.backends.ModelBackend',
@ -520,6 +523,20 @@ SOCIAL_AUTH_GITHUB_TEAM_SECRET = ''
SOCIAL_AUTH_GITHUB_TEAM_ID = ''
SOCIAL_AUTH_GITHUB_TEAM_SCOPE = ['user:email', 'read:org']
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_SCOPE = ['user:email', 'read:org']
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SCOPE = ['user:email', 'read:org']
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID = ''
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SCOPE = ['user:email', 'read:org']
SOCIAL_AUTH_AZUREAD_OAUTH2_KEY = ''
SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET = ''

View File

@ -842,6 +842,298 @@ register(
placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER,
)
###############################################################################
# GITHUB ENTERPRISE OAUTH2 AUTHENTICATION SETTINGS
###############################################################################
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_CALLBACK_URL',
field_class=fields.CharField,
read_only=True,
default=SocialAuthCallbackURL('github-enterprise'),
label=_('GitHub Enterprise OAuth2 Callback URL'),
help_text=_('Provide this URL as the callback URL for your application as part '
'of your registration process. Refer to the Ansible Tower '
'documentation for more detail.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise',
depends_on=['TOWER_URL_BASE'],
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise URL'),
help_text=_('The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise '
'documentation for more details.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise API URL'),
help_text=_('The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github '
'Enterprise documentation for more details.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise OAuth2 Key'),
help_text=_('The OAuth2 key (Client ID) from your GitHub Enterprise developer application.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise OAuth2 Secret'),
help_text=_('The OAuth2 secret (Client Secret) from your GitHub Enterprise developer application.'),
category=_('GitHub OAuth2'),
category_slug='github-enterprise',
encrypted=True,
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP',
field_class=SocialOrganizationMapField,
allow_null=True,
default=None,
label=_('GitHub Enterprise OAuth2 Organization Map'),
help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT,
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise',
placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER,
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP',
field_class=SocialTeamMapField,
allow_null=True,
default=None,
label=_('GitHub Enterprise OAuth2 Team Map'),
help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT,
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise',
placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER,
)
###############################################################################
# GITHUB ENTERPRISE ORG OAUTH2 AUTHENTICATION SETTINGS
###############################################################################
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_CALLBACK_URL',
field_class=fields.CharField,
read_only=True,
default=SocialAuthCallbackURL('github-enterprise-org'),
label=_('GitHub Enterprise Organization OAuth2 Callback URL'),
help_text=_('Provide this URL as the callback URL for your application as part '
'of your registration process. Refer to the Ansible Tower '
'documentation for more detail.'),
category=_('GitHub Enterprise Organization OAuth2'),
category_slug='github-enterprise-org',
depends_on=['TOWER_URL_BASE'],
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Organization URL'),
help_text=_('The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise '
'documentation for more details.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise-org',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Organization API URL'),
help_text=_('The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github '
'Enterprise documentation for more details.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise-org',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Organization OAuth2 Key'),
help_text=_('The OAuth2 key (Client ID) from your GitHub Enterprise organization application.'),
category=_('GitHub Enterprise Organization OAuth2'),
category_slug='github-enterprise-org',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Organization OAuth2 Secret'),
help_text=_('The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.'),
category=_('GitHub Enterprise Organization OAuth2'),
category_slug='github-enterprise-org',
encrypted=True,
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Organization Name'),
help_text=_('The name of your GitHub Enterprise organization, as used in your '
'organization\'s URL: https://github.com/<yourorg>/.'),
category=_('GitHub Enterprise Organization OAuth2'),
category_slug='github-enterprise-org',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP',
field_class=SocialOrganizationMapField,
allow_null=True,
default=None,
label=_('GitHub Enterprise Organization OAuth2 Organization Map'),
help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT,
category=_('GitHub Enterprise Organization OAuth2'),
category_slug='github-enterprise-org',
placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER,
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP',
field_class=SocialTeamMapField,
allow_null=True,
default=None,
label=_('GitHub Enterprise Organization OAuth2 Team Map'),
help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT,
category=_('GitHub Enterprise Organization OAuth2'),
category_slug='github-enterprise-org',
placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER,
)
###############################################################################
# GITHUB ENTERPRISE TEAM OAUTH2 AUTHENTICATION SETTINGS
###############################################################################
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_CALLBACK_URL',
field_class=fields.CharField,
read_only=True,
default=SocialAuthCallbackURL('github-enterprise-team'),
label=_('GitHub Enterprise Team OAuth2 Callback URL'),
help_text=_('Create an organization-owned application at '
'https://github.com/organizations/<yourorg>/settings/applications '
'and obtain an OAuth2 key (Client ID) and secret (Client Secret). '
'Provide this URL as the callback URL for your application.'),
category=_('GitHub Enterprise Team OAuth2'),
category_slug='github-enterprise-team',
depends_on=['TOWER_URL_BASE'],
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Team URL'),
help_text=_('The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise '
'documentation for more details.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise-team',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Team API URL'),
help_text=_('The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github '
'Enterprise documentation for more details.'),
category=_('GitHub Enterprise OAuth2'),
category_slug='github-enterprise-team',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Team OAuth2 Key'),
help_text=_('The OAuth2 key (Client ID) from your GitHub Enterprise organization application.'),
category=_('GitHub Enterprise Team OAuth2'),
category_slug='github-enterprise-team',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Team OAuth2 Secret'),
help_text=_('The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.'),
category=_('GitHub Enterprise Team OAuth2'),
category_slug='github-enterprise-team',
encrypted=True,
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID',
field_class=fields.CharField,
allow_blank=True,
default='',
label=_('GitHub Enterprise Team ID'),
help_text=_('Find the numeric team ID using the Github Enterprise API: '
'http://fabian-kostadinov.github.io/2015/01/16/how-to-find-a-github-team-id/.'),
category=_('GitHub Enterprise Team OAuth2'),
category_slug='github-enterprise-team',
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP',
field_class=SocialOrganizationMapField,
allow_null=True,
default=None,
label=_('GitHub Enterprise Team OAuth2 Organization Map'),
help_text=SOCIAL_AUTH_ORGANIZATION_MAP_HELP_TEXT,
category=_('GitHub Enterprise Team OAuth2'),
category_slug='github-enterprise-team',
placeholder=SOCIAL_AUTH_ORGANIZATION_MAP_PLACEHOLDER,
)
register(
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP',
field_class=SocialTeamMapField,
allow_null=True,
default=None,
label=_('GitHub Enterprise Team OAuth2 Team Map'),
help_text=SOCIAL_AUTH_TEAM_MAP_HELP_TEXT,
category=_('GitHub Enterprise Team OAuth2'),
category_slug='github-enterprise-team',
placeholder=SOCIAL_AUTH_TEAM_MAP_PLACEHOLDER,
)
###############################################################################
# MICROSOFT AZURE ACTIVE DIRECTORY SETTINGS
###############################################################################

View File

@ -187,6 +187,26 @@ class AuthenticationBackendsField(fields.StringListField):
'SOCIAL_AUTH_GITHUB_TEAM_SECRET',
'SOCIAL_AUTH_GITHUB_TEAM_ID',
]),
('social_core.backends.github_enterprise.GithubEnterpriseOAuth2', [
'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET',
]),
('social_core.backends.github_enterprise.GithubEnterpriseOrganizationOAuth2', [
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME',
]),
('social_core.backends.github_enterprise.GithubEnterpriseTeamOAuth2', [
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET',
'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID',
]),
('social_core.backends.azuread.AzureADOAuth2', [
'SOCIAL_AUTH_AZUREAD_OAUTH2_KEY',
'SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET',

View File

@ -165,6 +165,41 @@ function AWXLogin({ alt, i18n, isAuthenticated }) {
</LoginMainFooterLinksItem>
);
}
if (authKey === 'github-enterprise') {
return (
<LoginMainFooterLinksItem href={loginUrl} key={authKey}>
<Tooltip
content={i18n._(t`Sign in with GitHub Enterprise`)}
>
<GithubIcon />
</Tooltip>
</LoginMainFooterLinksItem>
);
}
if (authKey === 'github-enterprise-org') {
return (
<LoginMainFooterLinksItem href={loginUrl} key={authKey}>
<Tooltip
content={i18n._(
t`Sign in with GitHub Enterprise Organizations`
)}
>
<GithubIcon />
</Tooltip>
</LoginMainFooterLinksItem>
);
}
if (authKey === 'github-enterprise-team') {
return (
<LoginMainFooterLinksItem href={loginUrl} key={authKey}>
<Tooltip
content={i18n._(t`Sign in with GitHub Enterprise Teams`)}
>
<GithubIcon />
</Tooltip>
</LoginMainFooterLinksItem>
);
}
if (authKey === 'google-oauth2') {
return (
<LoginMainFooterLinksItem href={loginUrl} key={authKey}>

View File

@ -8,6 +8,9 @@ import GitHubDetail from './GitHubDetail';
import GitHubEdit from './GitHubEdit';
import GitHubOrgEdit from './GitHubOrgEdit';
import GitHubTeamEdit from './GitHubTeamEdit';
import GitHubEnterpriseEdit from './GitHubEnterpriseEdit';
import GitHubEnterpriseOrgEdit from './GitHubEnterpriseOrgEdit';
import GitHubEnterpriseTeamEdit from './GitHubEnterpriseTeamEdit';
function GitHub({ i18n }) {
const baseURL = '/settings/github';
@ -40,6 +43,15 @@ function GitHub({ i18n }) {
<Route path={`${baseURL}/team/edit`}>
<GitHubTeamEdit />
</Route>
<Route path={`${baseURL}/enterprise/edit`}>
<GitHubEnterpriseEdit />
</Route>
<Route path={`${baseURL}/enterprise_organization/edit`}>
<GitHubEnterpriseOrgEdit />
</Route>
<Route path={`${baseURL}/enterprise_team/edit`}>
<GitHubEnterpriseTeamEdit />
</Route>
<Route key="not-found" path={`${baseURL}/*`}>
<ContentError isNotFound>
<Link to={`${baseURL}/default/details`}>

View File

@ -48,6 +48,44 @@ describe('<GitHub />', () => {
SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP: {},
},
});
SettingsAPI.readCategory.mockResolvedValueOnce({
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: 'https://localhost/url',
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: 'https://localhost/apiurl',
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: 'ent_key',
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '$encrypted',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: {},
},
});
SettingsAPI.readCategory.mockResolvedValueOnce({
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise-org/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: 'https://localhost/url',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL: 'https://localhost/apiurl',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY: 'ent_org_key',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME: 'ent_org_name',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: {},
},
});
SettingsAPI.readCategory.mockResolvedValueOnce({
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise-team/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: 'https://localhost/url',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL: 'https://localhost/apiurl',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY: 'ent_team_key',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID: 'ent_team_id',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: {},
},
});
});
afterEach(() => {

View File

@ -31,21 +31,33 @@ function GitHubDetail({ i18n }) {
{ data: gitHubDefault },
{ data: gitHubOrganization },
{ data: gitHubTeam },
{ data: gitHubEnterprise },
{ data: gitHubEnterpriseOrganization },
{ data: gitHubEnterpriseTeam },
] = await Promise.all([
SettingsAPI.readCategory('github'),
SettingsAPI.readCategory('github-org'),
SettingsAPI.readCategory('github-team'),
SettingsAPI.readCategory('github-enterprise'),
SettingsAPI.readCategory('github-enterprise-org'),
SettingsAPI.readCategory('github-enterprise-team'),
]);
return {
default: gitHubDefault,
organization: gitHubOrganization,
team: gitHubTeam,
enterprise: gitHubEnterprise,
enterprise_organization: gitHubEnterpriseOrganization,
enterprise_team: gitHubEnterpriseTeam,
};
}, []),
{
default: null,
organization: null,
team: null,
enterprise: null,
enterprise_organization: null,
enterprise_team: null,
}
);
@ -79,6 +91,21 @@ function GitHubDetail({ i18n }) {
link: `${baseURL}/team/details`,
id: 2,
},
{
name: i18n._(t`GitHub Enterprise`),
link: `${baseURL}/enterprise/details`,
id: 3,
},
{
name: i18n._(t`GitHub Enterprise Organization`),
link: `${baseURL}/enterprise_organization/details`,
id: 4,
},
{
name: i18n._(t`GitHub Enterprise Team`),
link: `${baseURL}/enterprise_team/details`,
id: 5,
},
];
if (!Object.keys(gitHubDetails).includes(category)) {

View File

@ -51,6 +51,44 @@ const mockTeam = {
SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP: {},
},
};
const mockEnterprise = {
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: 'https://localhost/enterpriseurl',
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: 'https://localhost/enterpriseapi',
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: 'foobar',
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: null,
},
};
const mockEnterpriseOrg = {
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise-org/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: 'https://localhost/orgurl',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL: 'https://localhost/orgapi',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY: 'foobar',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME: 'foo',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: null,
},
};
const mockEnterpriseTeam = {
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise-team/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: 'https://localhost/teamurl',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL: 'https://localhost/teamapi',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY: 'foobar',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID: 'foo',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: null,
},
};
describe('<GitHubDetail />', () => {
describe('Default', () => {
@ -60,6 +98,9 @@ describe('<GitHubDetail />', () => {
SettingsAPI.readCategory.mockResolvedValueOnce(mockDefault);
SettingsAPI.readCategory.mockResolvedValueOnce(mockOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockTeam);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterprise);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseTeam);
useRouteMatch.mockImplementation(() => ({
url: '/settings/github/default/details',
path: '/settings/github/:category/details',
@ -90,6 +131,9 @@ describe('<GitHubDetail />', () => {
'GitHub Default',
'GitHub Organization',
'GitHub Team',
'GitHub Enterprise',
'GitHub Enterprise Organization',
'GitHub Enterprise Team',
];
wrapper.find('RoutedTabs li').forEach((tab, index) => {
expect(tab.text()).toEqual(expectedTabs[index]);
@ -149,6 +193,9 @@ describe('<GitHubDetail />', () => {
SettingsAPI.readCategory.mockResolvedValueOnce(mockDefault);
SettingsAPI.readCategory.mockResolvedValueOnce(mockOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockTeam);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterprise);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseTeam);
useRouteMatch.mockImplementation(() => ({
url: '/settings/github/organization/details',
path: '/settings/github/:category/details',
@ -198,6 +245,9 @@ describe('<GitHubDetail />', () => {
SettingsAPI.readCategory.mockResolvedValueOnce(mockDefault);
SettingsAPI.readCategory.mockResolvedValueOnce(mockOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockTeam);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterprise);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseTeam);
useRouteMatch.mockImplementation(() => ({
url: '/settings/github/team/details',
path: '/settings/github/:category/details',
@ -236,6 +286,199 @@ describe('<GitHubDetail />', () => {
});
});
describe('Enterprise', () => {
let wrapper;
beforeAll(async () => {
SettingsAPI.readCategory.mockResolvedValueOnce(mockDefault);
SettingsAPI.readCategory.mockResolvedValueOnce(mockOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockTeam);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterprise);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseTeam);
useRouteMatch.mockImplementation(() => ({
url: '/settings/github/enterprise/details',
path: '/settings/github/:category/details',
params: { category: 'enterprise' },
}));
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubDetail />
</SettingsProvider>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
afterAll(() => {
wrapper.unmount();
jest.clearAllMocks();
});
test('should render expected details', () => {
assertDetail(
wrapper,
'GitHub Enterprise OAuth2 Callback URL',
'https://towerhost/sso/complete/github-enterprise/'
);
assertDetail(
wrapper,
'GitHub Enterprise URL',
'https://localhost/enterpriseurl'
);
assertDetail(
wrapper,
'GitHub Enterprise API URL',
'https://localhost/enterpriseapi'
);
assertDetail(wrapper, 'GitHub Enterprise OAuth2 Key', 'foobar');
assertDetail(wrapper, 'GitHub Enterprise OAuth2 Secret', 'Encrypted');
assertVariableDetail(
wrapper,
'GitHub Enterprise OAuth2 Organization Map',
'{}'
);
assertVariableDetail(wrapper, 'GitHub Enterprise OAuth2 Team Map', '{}');
});
});
describe('Enterprise Org', () => {
let wrapper;
beforeAll(async () => {
SettingsAPI.readCategory.mockResolvedValueOnce(mockDefault);
SettingsAPI.readCategory.mockResolvedValueOnce(mockOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockTeam);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterprise);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseTeam);
useRouteMatch.mockImplementation(() => ({
url: '/settings/github/enterprise_organization/details',
path: '/settings/github/:category/details',
params: { category: 'enterprise_organization' },
}));
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubDetail />
</SettingsProvider>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
afterAll(() => {
wrapper.unmount();
jest.clearAllMocks();
});
test('should render expected details', () => {
assertDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Callback URL',
'https://towerhost/sso/complete/github-enterprise-org/'
);
assertDetail(
wrapper,
'GitHub Enterprise Organization URL',
'https://localhost/orgurl'
);
assertDetail(
wrapper,
'GitHub Enterprise Organization API URL',
'https://localhost/orgapi'
);
assertDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Key',
'foobar'
);
assertDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Secret',
'Encrypted'
);
assertDetail(wrapper, 'GitHub Enterprise Organization Name', 'foo');
assertVariableDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Organization Map',
'{}'
);
assertVariableDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Team Map',
'{}'
);
});
});
describe('Enterprise Team', () => {
let wrapper;
beforeAll(async () => {
SettingsAPI.readCategory.mockResolvedValueOnce(mockDefault);
SettingsAPI.readCategory.mockResolvedValueOnce(mockOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockTeam);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterprise);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseOrg);
SettingsAPI.readCategory.mockResolvedValueOnce(mockEnterpriseTeam);
useRouteMatch.mockImplementation(() => ({
url: '/settings/github/enterprise_team/details',
path: '/settings/github/:category/details',
params: { category: 'enterprise_team' },
}));
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubDetail />
</SettingsProvider>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
afterAll(() => {
wrapper.unmount();
jest.clearAllMocks();
});
test('should render expected details', () => {
assertDetail(
wrapper,
'GitHub Enterprise Team OAuth2 Callback URL',
'https://towerhost/sso/complete/github-enterprise-team/'
);
assertDetail(
wrapper,
'GitHub Enterprise Team URL',
'https://localhost/teamurl'
);
assertDetail(
wrapper,
'GitHub Enterprise Team API URL',
'https://localhost/teamapi'
);
assertDetail(wrapper, 'GitHub Enterprise Team OAuth2 Key', 'foobar');
assertDetail(
wrapper,
'GitHub Enterprise Team OAuth2 Secret',
'Encrypted'
);
assertDetail(wrapper, 'GitHub Enterprise Team ID', 'foo');
assertVariableDetail(
wrapper,
'GitHub Enterprise Team OAuth2 Organization Map',
'{}'
);
assertVariableDetail(
wrapper,
'GitHub Enterprise Team OAuth2 Team Map',
'{}'
);
});
});
describe('Redirect', () => {
test('should render redirect when user navigates to erroneous category', async () => {
let wrapper;

View File

@ -0,0 +1,151 @@
import React, { useCallback, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { Formik } from 'formik';
import { Form } from '@patternfly/react-core';
import { CardBody } from '../../../../components/Card';
import ContentError from '../../../../components/ContentError';
import ContentLoading from '../../../../components/ContentLoading';
import { FormSubmitError } from '../../../../components/FormField';
import { FormColumnLayout } from '../../../../components/FormLayout';
import { useSettings } from '../../../../contexts/Settings';
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
import {
EncryptedField,
InputField,
ObjectField,
} from '../../shared/SharedFields';
import { formatJson } from '../../shared/settingUtils';
import useModal from '../../../../util/useModal';
import useRequest from '../../../../util/useRequest';
import { SettingsAPI } from '../../../../api';
function GitHubEnterpriseEdit() {
const history = useHistory();
const { isModalOpen, toggleModal, closeModal } = useModal();
const { PUT: options } = useSettings();
const { isLoading, error, request: fetchGithub, result: github } = useRequest(
useCallback(async () => {
const { data } = await SettingsAPI.readCategory('github-enterprise');
const mergedData = {};
Object.keys(data).forEach(key => {
if (!options[key]) {
return;
}
mergedData[key] = options[key];
mergedData[key].value = data[key];
});
return mergedData;
}, [options]),
null
);
useEffect(() => {
fetchGithub();
}, [fetchGithub]);
const { error: submitError, request: submitForm } = useRequest(
useCallback(
async values => {
await SettingsAPI.updateAll(values);
history.push('/settings/github/enterprise/details');
},
[history]
),
null
);
const handleSubmit = async form => {
await submitForm({
...form,
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: formatJson(
form.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP
),
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: formatJson(
form.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP
),
});
};
const handleRevertAll = async () => {
const defaultValues = Object.assign(
...Object.entries(github).map(([key, value]) => ({
[key]: value.default,
}))
);
await submitForm(defaultValues);
closeModal();
};
const handleCancel = () => {
history.push('/settings/github/enterprise/details');
};
const initialValues = fields =>
Object.keys(fields).reduce((acc, key) => {
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
acc[key] = fields[key].value
? JSON.stringify(fields[key].value, null, 2)
: emptyDefault;
} else {
acc[key] = fields[key].value ?? '';
}
return acc;
}, {});
return (
<CardBody>
{isLoading && <ContentLoading />}
{!isLoading && error && <ContentError error={error} />}
{!isLoading && github && (
<Formik initialValues={initialValues(github)} onSubmit={handleSubmit}>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_URL"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_URL}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY}
/>
<EncryptedField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET}
/>
<ObjectField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP}
/>
<ObjectField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP}
/>
{submitError && <FormSubmitError error={submitError} />}
</FormColumnLayout>
<RevertFormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
onRevert={toggleModal}
/>
{isModalOpen && (
<RevertAllAlert
onClose={closeModal}
onRevertAll={handleRevertAll}
/>
)}
</Form>
)}
</Formik>
)}
</CardBody>
);
}
export default GitHubEnterpriseEdit;

View File

@ -0,0 +1,196 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { createMemoryHistory } from 'history';
import {
mountWithContexts,
waitForElement,
} from '../../../../../testUtils/enzymeHelpers';
import mockAllOptions from '../../shared/data.allSettingOptions.json';
import { SettingsProvider } from '../../../../contexts/Settings';
import { SettingsAPI } from '../../../../api';
import GitHubEnterpriseEdit from './GitHubEnterpriseEdit';
jest.mock('../../../../api/models/Settings');
SettingsAPI.updateAll.mockResolvedValue({});
SettingsAPI.readCategory.mockResolvedValue({
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: null,
},
});
describe('<GitHubEnterpriseEdit />', () => {
let wrapper;
let history;
afterEach(() => {
wrapper.unmount();
jest.clearAllMocks();
});
beforeEach(async () => {
history = createMemoryHistory({
initialEntries: ['/settings/github/enterprise/edit'],
});
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubEnterpriseEdit />
</SettingsProvider>,
{
context: { router: { history } },
}
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
test('initially renders without crashing', () => {
expect(wrapper.find('GitHubEnterpriseEdit').length).toBe(1);
});
test('should display expected form fields', async () => {
expect(
wrapper.find('FormGroup[label="GitHub Enterprise URL"]').length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise API URL"]').length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise OAuth2 Key"]').length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise OAuth2 Secret"]').length
).toBe(1);
expect(
wrapper.find(
'FormGroup[label="GitHub Enterprise OAuth2 Organization Map"]'
).length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise OAuth2 Team Map"]')
.length
).toBe(1);
});
test('should successfully send default values to api on form revert all', async () => {
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
await act(async () => {
wrapper
.find('button[aria-label="Revert all to default"]')
.invoke('onClick')();
});
wrapper.update();
expect(wrapper.find('RevertAllAlert')).toHaveLength(1);
await act(async () => {
wrapper
.find('RevertAllAlert button[aria-label="Confirm revert all"]')
.invoke('onClick')();
});
wrapper.update();
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: null,
});
});
test('should successfully send request to api on form submission', async () => {
act(() => {
wrapper
.find(
'FormGroup[fieldId="SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET"] button[aria-label="Revert"]'
)
.invoke('onClick')();
wrapper
.find('input#SOCIAL_AUTH_GITHUB_ENTERPRISE_URL')
.simulate('change', {
target: {
value: 'https://localhost',
name: 'SOCIAL_AUTH_GITHUB_ENTERPRISE_URL',
},
});
wrapper
.find('CodeMirrorInput#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP')
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
});
wrapper.update();
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: 'https://localhost',
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: {
Default: {
users: false,
},
},
});
});
test('should navigate to github enterprise detail on successful submission', async () => {
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
expect(history.location.pathname).toEqual(
'/settings/github/enterprise/details'
);
});
test('should navigate to github enterprise detail when cancel is clicked', async () => {
await act(async () => {
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
});
expect(history.location.pathname).toEqual(
'/settings/github/enterprise/details'
);
});
test('should display error message on unsuccessful submission', async () => {
const error = {
response: {
data: { detail: 'An error occurred' },
},
};
SettingsAPI.updateAll.mockImplementation(() => Promise.reject(error));
expect(wrapper.find('FormSubmitError').length).toBe(0);
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
wrapper.update();
expect(wrapper.find('FormSubmitError').length).toBe(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
});
test('should display ContentError on throw', async () => {
SettingsAPI.readCategory.mockImplementationOnce(() =>
Promise.reject(new Error())
);
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubEnterpriseEdit />
</SettingsProvider>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('ContentError').length).toBe(1);
});
});

View File

@ -0,0 +1 @@
export { default } from './GitHubEnterpriseEdit';

View File

@ -0,0 +1,157 @@
import React, { useCallback, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { Formik } from 'formik';
import { Form } from '@patternfly/react-core';
import { CardBody } from '../../../../components/Card';
import ContentError from '../../../../components/ContentError';
import ContentLoading from '../../../../components/ContentLoading';
import { FormSubmitError } from '../../../../components/FormField';
import { FormColumnLayout } from '../../../../components/FormLayout';
import { useSettings } from '../../../../contexts/Settings';
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
import {
EncryptedField,
InputField,
ObjectField,
} from '../../shared/SharedFields';
import { formatJson } from '../../shared/settingUtils';
import useModal from '../../../../util/useModal';
import useRequest from '../../../../util/useRequest';
import { SettingsAPI } from '../../../../api';
function GitHubEnterpriseOrgEdit() {
const history = useHistory();
const { isModalOpen, toggleModal, closeModal } = useModal();
const { PUT: options } = useSettings();
const { isLoading, error, request: fetchGithub, result: github } = useRequest(
useCallback(async () => {
const { data } = await SettingsAPI.readCategory('github-enterprise-org');
const mergedData = {};
Object.keys(data).forEach(key => {
if (!options[key]) {
return;
}
mergedData[key] = options[key];
mergedData[key].value = data[key];
});
return mergedData;
}, [options]),
null
);
useEffect(() => {
fetchGithub();
}, [fetchGithub]);
const { error: submitError, request: submitForm } = useRequest(
useCallback(
async values => {
await SettingsAPI.updateAll(values);
history.push('/settings/github/enterprise_organization/details');
},
[history]
),
null
);
const handleSubmit = async form => {
await submitForm({
...form,
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: formatJson(
form.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP
),
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: formatJson(
form.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP
),
});
};
const handleRevertAll = async () => {
const defaultValues = Object.assign(
...Object.entries(github).map(([key, value]) => ({
[key]: value.default,
}))
);
await submitForm(defaultValues);
closeModal();
};
const handleCancel = () => {
history.push('/settings/github/enterprise_organization/details');
};
const initialValues = fields =>
Object.keys(fields).reduce((acc, key) => {
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
acc[key] = fields[key].value
? JSON.stringify(fields[key].value, null, 2)
: emptyDefault;
} else {
acc[key] = fields[key].value ?? '';
}
return acc;
}, {});
return (
<CardBody>
{isLoading && <ContentLoading />}
{!isLoading && error && <ContentError error={error} />}
{!isLoading && github && (
<Formik initialValues={initialValues(github)} onSubmit={handleSubmit}>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY}
/>
<EncryptedField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME}
/>
<ObjectField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP"
config={
github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP
}
/>
<ObjectField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP}
/>
{submitError && <FormSubmitError error={submitError} />}
</FormColumnLayout>
<RevertFormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
onRevert={toggleModal}
/>
{isModalOpen && (
<RevertAllAlert
onClose={closeModal}
onRevertAll={handleRevertAll}
/>
)}
</Form>
)}
</Formik>
)}
</CardBody>
);
}
export default GitHubEnterpriseOrgEdit;

View File

@ -0,0 +1,212 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { createMemoryHistory } from 'history';
import {
mountWithContexts,
waitForElement,
} from '../../../../../testUtils/enzymeHelpers';
import mockAllOptions from '../../shared/data.allSettingOptions.json';
import { SettingsProvider } from '../../../../contexts/Settings';
import { SettingsAPI } from '../../../../api';
import GitHubEnterpriseOrgEdit from './GitHubEnterpriseOrgEdit';
jest.mock('../../../../api/models/Settings');
SettingsAPI.updateAll.mockResolvedValue({});
SettingsAPI.readCategory.mockResolvedValue({
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise-org/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: null,
},
});
describe('<GitHubEnterpriseOrgEdit />', () => {
let wrapper;
let history;
afterEach(() => {
wrapper.unmount();
jest.clearAllMocks();
});
beforeEach(async () => {
history = createMemoryHistory({
initialEntries: ['/settings/github/enterprise_organization/edit'],
});
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubEnterpriseOrgEdit />
</SettingsProvider>,
{
context: { router: { history } },
}
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
test('initially renders without crashing', () => {
expect(wrapper.find('GitHubEnterpriseOrgEdit').length).toBe(1);
});
test('should display expected form fields', async () => {
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Organization URL"]')
.length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Organization API URL"]')
.length
).toBe(1);
expect(
wrapper.find(
'FormGroup[label="GitHub Enterprise Organization OAuth2 Key"]'
).length
).toBe(1);
expect(
wrapper.find(
'FormGroup[label="GitHub Enterprise Organization OAuth2 Secret"]'
).length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Organization Name"]')
.length
).toBe(1);
expect(
wrapper.find(
'FormGroup[label="GitHub Enterprise Organization OAuth2 Organization Map"]'
).length
).toBe(1);
expect(
wrapper.find(
'FormGroup[label="GitHub Enterprise Organization OAuth2 Team Map"]'
).length
).toBe(1);
});
test('should successfully send default values to api on form revert all', async () => {
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
await act(async () => {
wrapper
.find('button[aria-label="Revert all to default"]')
.invoke('onClick')();
});
wrapper.update();
expect(wrapper.find('RevertAllAlert')).toHaveLength(1);
await act(async () => {
wrapper
.find('RevertAllAlert button[aria-label="Confirm revert all"]')
.invoke('onClick')();
});
wrapper.update();
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: null,
});
});
test('should successfully send request to api on form submission', async () => {
act(() => {
wrapper
.find(
'FormGroup[fieldId="SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET"] button[aria-label="Revert"]'
)
.invoke('onClick')();
wrapper
.find('input#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL')
.simulate('change', {
target: {
value: 'https://localhost',
name: 'SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL',
},
});
wrapper
.find(
'CodeMirrorInput#SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP'
)
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
});
wrapper.update();
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: 'https://localhost',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: {
Default: {
users: false,
},
},
});
});
test('should navigate to github enterprise org detail on successful submission', async () => {
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
expect(history.location.pathname).toEqual(
'/settings/github/enterprise_organization/details'
);
});
test('should navigate to github enterprise org detail when cancel is clicked', async () => {
await act(async () => {
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
});
expect(history.location.pathname).toEqual(
'/settings/github/enterprise_organization/details'
);
});
test('should display error message on unsuccessful submission', async () => {
const error = {
response: {
data: { detail: 'An error occurred' },
},
};
SettingsAPI.updateAll.mockImplementation(() => Promise.reject(error));
expect(wrapper.find('FormSubmitError').length).toBe(0);
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
wrapper.update();
expect(wrapper.find('FormSubmitError').length).toBe(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
});
test('should display ContentError on throw', async () => {
SettingsAPI.readCategory.mockImplementationOnce(() =>
Promise.reject(new Error())
);
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubEnterpriseOrgEdit />
</SettingsProvider>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('ContentError').length).toBe(1);
});
});

View File

@ -0,0 +1 @@
export { default } from './GitHubEnterpriseOrgEdit';

View File

@ -0,0 +1,157 @@
import React, { useCallback, useEffect } from 'react';
import { useHistory } from 'react-router-dom';
import { Formik } from 'formik';
import { Form } from '@patternfly/react-core';
import { CardBody } from '../../../../components/Card';
import ContentError from '../../../../components/ContentError';
import ContentLoading from '../../../../components/ContentLoading';
import { FormSubmitError } from '../../../../components/FormField';
import { FormColumnLayout } from '../../../../components/FormLayout';
import { useSettings } from '../../../../contexts/Settings';
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
import {
EncryptedField,
InputField,
ObjectField,
} from '../../shared/SharedFields';
import { formatJson } from '../../shared/settingUtils';
import useModal from '../../../../util/useModal';
import useRequest from '../../../../util/useRequest';
import { SettingsAPI } from '../../../../api';
function GitHubEnterpriseTeamEdit() {
const history = useHistory();
const { isModalOpen, toggleModal, closeModal } = useModal();
const { PUT: options } = useSettings();
const { isLoading, error, request: fetchGithub, result: github } = useRequest(
useCallback(async () => {
const { data } = await SettingsAPI.readCategory('github-enterprise-team');
const mergedData = {};
Object.keys(data).forEach(key => {
if (!options[key]) {
return;
}
mergedData[key] = options[key];
mergedData[key].value = data[key];
});
return mergedData;
}, [options]),
null
);
useEffect(() => {
fetchGithub();
}, [fetchGithub]);
const { error: submitError, request: submitForm } = useRequest(
useCallback(
async values => {
await SettingsAPI.updateAll(values);
history.push('/settings/github/enterprise_team/details');
},
[history]
),
null
);
const handleSubmit = async form => {
await submitForm({
...form,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: formatJson(
form.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP
),
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: formatJson(
form.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP
),
});
};
const handleRevertAll = async () => {
const defaultValues = Object.assign(
...Object.entries(github).map(([key, value]) => ({
[key]: value.default,
}))
);
await submitForm(defaultValues);
closeModal();
};
const handleCancel = () => {
history.push('/settings/github/enterprise_team/details');
};
const initialValues = fields =>
Object.keys(fields).reduce((acc, key) => {
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
acc[key] = fields[key].value
? JSON.stringify(fields[key].value, null, 2)
: emptyDefault;
} else {
acc[key] = fields[key].value ?? '';
}
return acc;
}, {});
return (
<CardBody>
{isLoading && <ContentLoading />}
{!isLoading && error && <ContentError error={error} />}
{!isLoading && github && (
<Formik initialValues={initialValues(github)} onSubmit={handleSubmit}>
{formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormColumnLayout>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY}
/>
<EncryptedField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET}
/>
<InputField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID}
/>
<ObjectField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP"
config={
github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP
}
/>
<ObjectField
name="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP"
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP}
/>
{submitError && <FormSubmitError error={submitError} />}
</FormColumnLayout>
<RevertFormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
onRevert={toggleModal}
/>
{isModalOpen && (
<RevertAllAlert
onClose={closeModal}
onRevertAll={handleRevertAll}
/>
)}
</Form>
)}
</Formik>
)}
</CardBody>
);
}
export default GitHubEnterpriseTeamEdit;

View File

@ -0,0 +1,206 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { createMemoryHistory } from 'history';
import {
mountWithContexts,
waitForElement,
} from '../../../../../testUtils/enzymeHelpers';
import mockAllOptions from '../../shared/data.allSettingOptions.json';
import { SettingsProvider } from '../../../../contexts/Settings';
import { SettingsAPI } from '../../../../api';
import GitHubEnterpriseTeamEdit from './GitHubEnterpriseTeamEdit';
jest.mock('../../../../api/models/Settings');
SettingsAPI.updateAll.mockResolvedValue({});
SettingsAPI.readCategory.mockResolvedValue({
data: {
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_CALLBACK_URL:
'https://towerhost/sso/complete/github-enterprise-team/',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET: '$encrypted$',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: null,
},
});
describe('<GitHubEnterpriseTeamEdit />', () => {
let wrapper;
let history;
afterEach(() => {
wrapper.unmount();
jest.clearAllMocks();
});
beforeEach(async () => {
history = createMemoryHistory({
initialEntries: ['/settings/github/enterprise_team/edit'],
});
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubEnterpriseTeamEdit />
</SettingsProvider>,
{
context: { router: { history } },
}
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
});
test('initially renders without crashing', () => {
expect(wrapper.find('GitHubEnterpriseTeamEdit').length).toBe(1);
});
test('should display expected form fields', async () => {
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Team URL"]').length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Team API URL"]').length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Team OAuth2 Key"]')
.length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Team OAuth2 Secret"]')
.length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Team ID"]').length
).toBe(1);
expect(
wrapper.find(
'FormGroup[label="GitHub Enterprise Team OAuth2 Organization Map"]'
).length
).toBe(1);
expect(
wrapper.find('FormGroup[label="GitHub Enterprise Team OAuth2 Team Map"]')
.length
).toBe(1);
});
test('should successfully send default values to api on form revert all', async () => {
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
await act(async () => {
wrapper
.find('button[aria-label="Revert all to default"]')
.invoke('onClick')();
});
wrapper.update();
expect(wrapper.find('RevertAllAlert')).toHaveLength(1);
await act(async () => {
wrapper
.find('RevertAllAlert button[aria-label="Confirm revert all"]')
.invoke('onClick')();
});
wrapper.update();
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: null,
});
});
test('should successfully send request to api on form submission', async () => {
act(() => {
wrapper
.find(
'FormGroup[fieldId="SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET"] button[aria-label="Revert"]'
)
.invoke('onClick')();
wrapper
.find('input#SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL')
.simulate('change', {
target: {
value: 'https://localhost',
name: 'SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL',
},
});
wrapper
.find(
'CodeMirrorInput#SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP'
)
.invoke('onChange')('{\n"Default":{\n"users":\nfalse\n}\n}');
});
wrapper.update();
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: 'https://localhost',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: {
Default: {
users: false,
},
},
});
});
test('should navigate to github enterprise team detail on successful submission', async () => {
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
expect(history.location.pathname).toEqual(
'/settings/github/enterprise_team/details'
);
});
test('should navigate to github enterprise team detail when cancel is clicked', async () => {
await act(async () => {
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
});
expect(history.location.pathname).toEqual(
'/settings/github/enterprise_team/details'
);
});
test('should display error message on unsuccessful submission', async () => {
const error = {
response: {
data: { detail: 'An error occurred' },
},
};
SettingsAPI.updateAll.mockImplementation(() => Promise.reject(error));
expect(wrapper.find('FormSubmitError').length).toBe(0);
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
await act(async () => {
wrapper.find('Form').invoke('onSubmit')();
});
wrapper.update();
expect(wrapper.find('FormSubmitError').length).toBe(1);
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
});
test('should display ContentError on throw', async () => {
SettingsAPI.readCategory.mockImplementationOnce(() =>
Promise.reject(new Error())
);
await act(async () => {
wrapper = mountWithContexts(
<SettingsProvider value={mockAllOptions.actions}>
<GitHubEnterpriseTeamEdit />
</SettingsProvider>
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('ContentError').length).toBe(1);
});
});

View File

@ -0,0 +1 @@
export { default } from './GitHubEnterpriseTeamEdit';

View File

@ -57,6 +57,17 @@ function Settings({ i18n }) {
'/settings/github/team': i18n._(t`GitHub Team`),
'/settings/github/team/details': i18n._(t`Details`),
'/settings/github/team/edit': i18n._(t`Edit Details`),
'/settings/github/enterprise': i18n._(t`GitHub Enterprise`),
'/settings/github/enterprise/details': i18n._(t`Details`),
'/settings/github/enterprise/edit': i18n._(t`Edit Details`),
'/settings/github/enterprise_organization': i18n._(
t`GitHub Enterprise Organization`
),
'/settings/github/enterprise_organization/details': i18n._(t`Details`),
'/settings/github/enterprise_organization/edit': i18n._(t`Edit Details`),
'/settings/github/enterprise_team': i18n._(t`GitHub Enterprise Team`),
'/settings/github/enterprise_team/details': i18n._(t`Details`),
'/settings/github/enterprise_team/edit': i18n._(t`Edit Details`),
'/settings/google_oauth2': i18n._(t`Google OAuth2`),
'/settings/google_oauth2/details': i18n._(t`Details`),
'/settings/google_oauth2/edit': i18n._(t`Edit Details`),

View File

@ -78,7 +78,7 @@
"REDHAT_USERNAME": {
"type": "string",
"label": "Red Hat customer username",
"help_text": "This username is used to retrieve license information and to send Automation Analytics",
"help_text": "This username is used to send data to Automation Analytics",
"category": "System",
"category_slug": "system",
"defined_in_file": false
@ -86,7 +86,23 @@
"REDHAT_PASSWORD": {
"type": "string",
"label": "Red Hat customer password",
"help_text": "This password is used to retrieve license information and to send Automation Analytics",
"help_text": "This password is used to send data to Automation Analytics",
"category": "System",
"category_slug": "system",
"defined_in_file": false
},
"SUBSCRIPTIONS_USERNAME": {
"type": "string",
"label": "Red Hat or Satellite username",
"help_text": "This username is used to retrieve subscription and content information",
"category": "System",
"category_slug": "system",
"defined_in_file": false
},
"SUBSCRIPTIONS_PASSWORD": {
"type": "string",
"label": "Red Hat or Satellite password",
"help_text": "This password is used to retrieve subscription and content information",
"category": "System",
"category_slug": "system",
"defined_in_file": false
@ -2449,6 +2465,238 @@
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_CALLBACK_URL": {
"type": "string",
"label": "GitHub Enterprise OAuth2 Callback URL",
"help_text": "Provide this URL as the callback URL for your application as part of your registration process. Refer to the Ansible Tower documentation for more detail.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": {
"type": "string",
"label": "GitHub Enterprise URL",
"help_text": "The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": {
"type": "string",
"label": "GitHub Enterprise API URL",
"help_text": "The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY": {
"type": "string",
"label": "GitHub Enterprise OAuth2 Key",
"help_text": "The OAuth2 key (Client ID) from your GitHub Enterprise developer application.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET": {
"type": "string",
"label": "GitHub Enterprise OAuth2 Secret",
"help_text": "The OAuth2 secret (Client Secret) from your GitHub Enterprise developer application.",
"category": "GitHub OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP": {
"type": "nested object",
"label": "GitHub Enterprise OAuth2 Organization Map",
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which Tower organizations based on their\nusername and email address. Configuration details are available in the Ansible\nTower documentation.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false,
"child": {
"type": "nested object",
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP": {
"type": "nested object",
"label": "GitHub Enterprise OAuth2 Team Map",
"help_text": "Mapping of team members (users) from social auth accounts. Configuration\ndetails are available in Tower documentation.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"defined_in_file": false,
"child": {
"type": "nested object",
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_CALLBACK_URL": {
"type": "string",
"label": "GitHub Enterprise Organization OAuth2 Callback URL",
"help_text": "Provide this URL as the callback URL for your application as part of your registration process. Refer to the Ansible Tower documentation for more detail.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL": {
"type": "string",
"label": "GitHub Enterprise Organization URL",
"help_text": "The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL": {
"type": "string",
"label": "GitHub Enterprise Organization API URL",
"help_text": "The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY": {
"type": "string",
"label": "GitHub Enterprise Organization OAuth2 Key",
"help_text": "The OAuth2 key (Client ID) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET": {
"type": "string",
"label": "GitHub Enterprise Organization OAuth2 Secret",
"help_text": "The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME": {
"type": "string",
"label": "GitHub Enterprise Organization Name",
"help_text": "The name of your GitHub Enterprise organization, as used in your organization's URL: https://github.com/<yourorg>/.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP": {
"type": "nested object",
"label": "GitHub Enterprise Organization OAuth2 Organization Map",
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which Tower organizations based on their\nusername and email address. Configuration details are available in the Ansible\nTower documentation.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false,
"child": {
"type": "nested object",
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP": {
"type": "nested object",
"label": "GitHub Enterprise Organization OAuth2 Team Map",
"help_text": "Mapping of team members (users) from social auth accounts. Configuration\ndetails are available in Tower documentation.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"defined_in_file": false,
"child": {
"type": "nested object",
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_CALLBACK_URL": {
"type": "string",
"label": "GitHub Enterprise Team OAuth2 Callback URL",
"help_text": "Create an organization-owned application at https://github.com/organizations/<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and secret (Client Secret). Provide this URL as the callback URL for your application.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL": {
"type": "string",
"label": "GitHub Enterprise Team URL",
"help_text": "The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL": {
"type": "string",
"label": "GitHub Enterprise Team API URL",
"help_text": "The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY": {
"type": "string",
"label": "GitHub Enterprise Team OAuth2 Key",
"help_text": "The OAuth2 key (Client ID) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET": {
"type": "string",
"label": "GitHub Enterprise Team OAuth2 Secret",
"help_text": "The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID": {
"type": "string",
"label": "GitHub Enterprise Team ID",
"help_text": "Find the numeric team ID using the Github Enterprise API: http://fabian-kostadinov.github.io/2015/01/16/how-to-find-a-github-team-id/.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP": {
"type": "nested object",
"label": "GitHub Enterprise Team OAuth2 Organization Map",
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which Tower organizations based on their\nusername and email address. Configuration details are available in the Ansible\nTower documentation.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false,
"child": {
"type": "nested object",
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP": {
"type": "nested object",
"label": "GitHub Enterprise Team OAuth2 Team Map",
"help_text": "Mapping of team members (users) from social auth accounts. Configuration\ndetails are available in Tower documentation.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"defined_in_file": false,
"child": {
"type": "nested object",
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_AZUREAD_OAUTH2_CALLBACK_URL": {
"type": "string",
"label": "Azure AD OAuth2 Callback URL",
@ -2745,29 +2993,6 @@
"category_slug": "system",
"default": true
},
"PENDO_TRACKING_STATE": {
"default": "off",
"type": "choice",
"required": true,
"label": "User Analytics Tracking State",
"help_text": "Enable or Disable User Analytics Tracking.",
"category": "UI",
"category_slug": "ui",
"choices": [
[
"off",
"Off"
],
[
"anonymous",
"Anonymous"
],
[
"detailed",
"Detailed"
]
]
},
"MANAGE_ORGANIZATION_AUTH": {
"type": "boolean",
"required": true,
@ -2821,7 +3046,7 @@
"type": "string",
"required": false,
"label": "Red Hat customer username",
"help_text": "This username is used to retrieve license information and to send Automation Analytics",
"help_text": "This username is used to send data to Automation Analytics",
"category": "System",
"category_slug": "system",
"default": ""
@ -2830,7 +3055,25 @@
"type": "string",
"required": false,
"label": "Red Hat customer password",
"help_text": "This password is used to retrieve license information and to send Automation Analytics",
"help_text": "This password is used to send data to Automation Analytics",
"category": "System",
"category_slug": "system",
"default": ""
},
"SUBSCRIPTIONS_USERNAME": {
"type": "string",
"required": false,
"label": "Red Hat or Satellite username",
"help_text": "This username is used to retrieve subscription and content information",
"category": "System",
"category_slug": "system",
"default": ""
},
"SUBSCRIPTIONS_PASSWORD": {
"type": "string",
"required": false,
"label": "Red Hat or Satellite password",
"help_text": "This password is used to retrieve subscription and content information",
"category": "System",
"category_slug": "system",
"default": ""
@ -3513,6 +3756,29 @@
"category_slug": "authentication",
"default": ""
},
"PENDO_TRACKING_STATE": {
"default": "off",
"type": "choice",
"required": true,
"label": "User Analytics Tracking State",
"help_text": "Enable or Disable User Analytics Tracking.",
"category": "UI",
"category_slug": "ui",
"choices": [
[
"off",
"Off"
],
[
"anonymous",
"Anonymous"
],
[
"detailed",
"Detailed"
]
]
},
"CUSTOM_LOGIN_INFO": {
"type": "string",
"required": false,
@ -6067,6 +6333,357 @@
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_URL": {
"type": "string",
"required": false,
"label": "GitHub Enterprise URL",
"help_text": "The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL": {
"type": "string",
"required": false,
"label": "GitHub Enterprise API URL",
"help_text": "The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY": {
"type": "string",
"required": false,
"label": "GitHub Enterprise OAuth2 Key",
"help_text": "The OAuth2 key (Client ID) from your GitHub Enterprise developer application.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET": {
"type": "string",
"required": false,
"label": "GitHub Enterprise OAuth2 Secret",
"help_text": "The OAuth2 secret (Client Secret) from your GitHub Enterprise developer application.",
"category": "GitHub OAuth2",
"category_slug": "github-enterprise",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP": {
"type": "nested object",
"required": false,
"label": "GitHub Enterprise OAuth2 Organization Map",
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which Tower organizations based on their\nusername and email address. Configuration details are available in the Ansible\nTower documentation.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"placeholder": {
"Default": {
"users": true
},
"Test Org": {
"admins": [
"admin@example.com"
],
"auditors": [
"auditor@example.com"
],
"users": true
},
"Test Org 2": {
"admins": [
"admin@example.com",
"/^tower-[^@]+*?@.*$/"
],
"remove_admins": true,
"users": "/^[^@].*?@example\\.com$/i",
"remove_users": true
}
},
"default": null,
"child": {
"type": "nested object",
"required": true,
"read_only": false,
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP": {
"type": "nested object",
"required": false,
"label": "GitHub Enterprise OAuth2 Team Map",
"help_text": "Mapping of team members (users) from social auth accounts. Configuration\ndetails are available in Tower documentation.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise",
"placeholder": {
"My Team": {
"organization": "Test Org",
"users": [
"/^[^@]+?@test\\.example\\.com$/"
],
"remove": true
},
"Other Team": {
"organization": "Test Org 2",
"users": "/^[^@]+?@test2\\.example\\.com$/i",
"remove": false
}
},
"default": null,
"child": {
"type": "nested object",
"required": true,
"read_only": false,
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Organization URL",
"help_text": "The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-org",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Organization API URL",
"help_text": "The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-org",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Organization OAuth2 Key",
"help_text": "The OAuth2 key (Client ID) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Organization OAuth2 Secret",
"help_text": "The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Organization Name",
"help_text": "The name of your GitHub Enterprise organization, as used in your organization's URL: https://github.com/<yourorg>/.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP": {
"type": "nested object",
"required": false,
"label": "GitHub Enterprise Organization OAuth2 Organization Map",
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which Tower organizations based on their\nusername and email address. Configuration details are available in the Ansible\nTower documentation.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"placeholder": {
"Default": {
"users": true
},
"Test Org": {
"admins": [
"admin@example.com"
],
"auditors": [
"auditor@example.com"
],
"users": true
},
"Test Org 2": {
"admins": [
"admin@example.com",
"/^tower-[^@]+*?@.*$/"
],
"remove_admins": true,
"users": "/^[^@].*?@example\\.com$/i",
"remove_users": true
}
},
"default": null,
"child": {
"type": "nested object",
"required": true,
"read_only": false,
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP": {
"type": "nested object",
"required": false,
"label": "GitHub Enterprise Organization OAuth2 Team Map",
"help_text": "Mapping of team members (users) from social auth accounts. Configuration\ndetails are available in Tower documentation.",
"category": "GitHub Enterprise Organization OAuth2",
"category_slug": "github-enterprise-org",
"placeholder": {
"My Team": {
"organization": "Test Org",
"users": [
"/^[^@]+?@test\\.example\\.com$/"
],
"remove": true
},
"Other Team": {
"organization": "Test Org 2",
"users": "/^[^@]+?@test2\\.example\\.com$/i",
"remove": false
}
},
"default": null,
"child": {
"type": "nested object",
"required": true,
"read_only": false,
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Team URL",
"help_text": "The URL for your Github Enterprise instance, e.g.: http(s)://hostname/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-team",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Team API URL",
"help_text": "The API URL for your GitHub Enterprise instance, e.g.: http(s)://hostname/api/v3/. Refer to Github Enterprise documentation for more details.",
"category": "GitHub Enterprise OAuth2",
"category_slug": "github-enterprise-team",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Team OAuth2 Key",
"help_text": "The OAuth2 key (Client ID) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Team OAuth2 Secret",
"help_text": "The OAuth2 secret (Client Secret) from your GitHub Enterprise organization application.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID": {
"type": "string",
"required": false,
"label": "GitHub Enterprise Team ID",
"help_text": "Find the numeric team ID using the Github Enterprise API: http://fabian-kostadinov.github.io/2015/01/16/how-to-find-a-github-team-id/.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"default": ""
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP": {
"type": "nested object",
"required": false,
"label": "GitHub Enterprise Team OAuth2 Organization Map",
"help_text": "Mapping to organization admins/users from social auth accounts. This setting\ncontrols which users are placed into which Tower organizations based on their\nusername and email address. Configuration details are available in the Ansible\nTower documentation.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"placeholder": {
"Default": {
"users": true
},
"Test Org": {
"admins": [
"admin@example.com"
],
"auditors": [
"auditor@example.com"
],
"users": true
},
"Test Org 2": {
"admins": [
"admin@example.com",
"/^tower-[^@]+*?@.*$/"
],
"remove_admins": true,
"users": "/^[^@].*?@example\\.com$/i",
"remove_users": true
}
},
"default": null,
"child": {
"type": "nested object",
"required": true,
"read_only": false,
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP": {
"type": "nested object",
"required": false,
"label": "GitHub Enterprise Team OAuth2 Team Map",
"help_text": "Mapping of team members (users) from social auth accounts. Configuration\ndetails are available in Tower documentation.",
"category": "GitHub Enterprise Team OAuth2",
"category_slug": "github-enterprise-team",
"placeholder": {
"My Team": {
"organization": "Test Org",
"users": [
"/^[^@]+?@test\\.example\\.com$/"
],
"remove": true
},
"Other Team": {
"organization": "Test Org 2",
"users": "/^[^@]+?@test2\\.example\\.com$/i",
"remove": false
}
},
"default": null,
"child": {
"type": "nested object",
"required": true,
"read_only": false,
"child": {
"type": "field",
"required": true,
"read_only": false
}
}
},
"SOCIAL_AUTH_AZUREAD_OAUTH2_KEY": {
"type": "string",
"required": false,
@ -6520,4 +7137,4 @@
}
}
}
}
}

View File

@ -5,6 +5,9 @@ When a user wants to log into Tower, she can explicitly choose some of the suppo
* Github OAuth2
* Github Organization OAuth2
* Github Team OAuth2
* Github Enterprise OAuth2
* Github Enterprise Organization OAuth2
* Github Enterprise Team OAuth2
* Microsoft Azure Active Directory (AD) OAuth2
On the other hand, the other authentication methods use the same types of login info as Tower (username and password), but authenticate using external auth systems rather than Tower's own database. If some of these methods are enabled, Tower will try authenticating using the enabled methods *before Tower's own authentication method*. The order of precedence is: